Из ошибки памяти в Java
-
27-09-2019 - |
Вопрос
Я получаю OutofMemoryError: Java Heap
фрагменты метода:
{
// step 1: I am creating a 2 dim array
int totalCombination = (int) Math.pow(2.0, (double) vowelCount);
// here vowelCount > 10
// step2: initializing my array
// step3: and using that array
}
Мой вопрос:
Каждый раз, когда этот метод называется, этот массив создается. Возможно ли, что массив не выпускается.
В Windows TaskManager я могу видеть память, используемую Java, чисто инкрементно. Так что не то, что в точечном размере куча меньше, но память повторяется и не выпущена как-то.
Пожалуйста, дайте мне знать, если вам нужно больше доклада.
Пожалуйста, помогите отладить ошибку.
Ануй
Часть кода, которая может вызвать ошибку:
INT TotalCombination = (int) math.pow (2.0, (двойной) vowelcount);
int lookupArray[][] = new int[totalCombination][vowelCount];
// initialize lookupArray
for (int i = 0; i < totalCombination; i++) {
for (int j = 0; j < vowelCount; j++) {
lookupArray[i][j] = 0;
}
}
// populate lookupArray
//vowelCount : number of vowels in a word
// if count is 2, then array will contain 00,01,10,11
for (int i = 1; i < totalCombination; i++) {
for (int c = 0; c < vowelCount; c++) {
lookupArray[i][c] = lookupArray[i - 1][c];
}
boolean flag = true;
for (int j = vowelCount - 1; j >= 0 && flag; j--) {
if (lookupArray[i - 1][j] == 1) {
lookupArray[i][j] = 0;
} else if (lookupArray[i - 1][j] == 0) {
lookupArray[i][j] = 1;
flag = false;
}
}
}
// this part total combination of a word having different combination of vowels in it.
for (int i = 0; i < totalCombination; i++) {
int vcount = vowelCount - 1;
StringBuffer stringBuffer = new StringBuffer();
for (int j = 0; j < word.length(); j++) {
if (wordArr[j] == 'a' || wordArr[j] == 'e' || wordArr[j] == 'i'
|| wordArr[j] == 'o' || wordArr[j] == 'u') {
if (lookupArray[i][vcount] == 1) {
stringBuffer.append(wordArr[j]);
}
vcount--;
} else {
stringBuffer.append(wordArr[j]);
}
}
Решение
Полномочия из двух вырастают экспоненциально. Если vowelCount
высокий, один массив один может легко вызвать OutOfMemoryError
(2^32 = 4GB
).
Вы можете попытаться настроить требование максимальной памяти VM (например, -Xmx512m
), но осознайте, что ваш алгоритм требует Много памяти. Отказ Вы можете найти лучший алгоритм, если вообще возможно.
Смотрите также
- Википедия: экспоненциальный рост
- Проблема пшеницы и шахматной доски - знаменитая анекдота, чтобы показать, насколько удивительно быстрые силы двух могут расти
java
Параметры командной строки приложений- "
-Xmxn
: Укажите максимальный размер пула распределения памяти. "
- "
После редактирования: Точно так же, как я ожидал, вы генерируете огромный массив, заполненный всеми двоичными возможностями. Вам редко нужно на самом деле сохранить весь этот массив в памяти. Вы можете просто генерировать каждую возможную комбинацию «On-Fly» и кормить его тем, кто нуждается в 0S и 1S «просто вовремя».
Имейте в виду, что это все еще экспоненциальный рост, поэтому, даже если вы позаботились о вашем требовании к памяти от O(2^N)
чтобы просто O(N)
, Ваше временное сложность все еще O(2^N)
.
Каждый раз, когда этот метод называется, этот массив создается. Возможно ли, что массив не выпускается.
Да, это очень возможно, если ссылка на массив когда-либо утечка, а потом что-то где-то держится на эту ссылку. Сборщик мусора на самом деле не заботится о том, что ты думаю, не мусор; Пока объект называется чем-то (и это не слабая ссылка и т. Д.), Это не мусор.
После выяснения того, что вы пытаетесь сделать, вот мое решение. Обратите внимание, что вообще не генерирует массив битов.
static void generate(String prefix, String suffix) {
int i = suffix.replaceAll("[aeiou].*", "").length();
if (i == suffix.length()) {
System.out.println(prefix + suffix);
} else {
generate(prefix + suffix.substring(0, i), suffix.substring(i + 1));
generate(prefix + suffix.substring(0, i+1), suffix.substring(i + 1));
}
}
// generate("", "apple");
Он использует Regex, чтобы найти, где находится следующий гласный. Вместо этого вы можете использовать регулярную петлю, и общий алгоритм все равно будет работать. Вы можете оптимизировать его, чтобы использовать StringBuilder
вместо этого (я в основном собираюсь в краткости и, надеюсь, ясность в этом фрагменте).
Вот альтернативное решение, которое использует split
предварительно нарезать входную строку на куски (O(N)
пространство), затем использует StringBuilder
генерировать все другие строки (O(N)
Космос).
static void generate(StringBuilder sb, String[] parts, int i) {
if (i == parts.length) {
System.out.println(sb.toString());
} else {
if ("aeiou".contains(parts[i])) {
generate(sb, parts, i + 1);
}
sb.append(parts[i]);
generate(sb, parts, i + 1);
sb.setLength(sb.length() - parts[i].length());
}
}
static void generate(String s) {
generate(
new StringBuilder(),
s.split("(?<=[aeiou])|(?=(?!^)[aeiou])"),
0
);
}
// generate("apple");
Регез расщепляется "apple"
в [ "a", "ppl", "e" ]
. Отказ Он разбивается везде после гласного или (если это не начало строки) везде перед гласным.
Теперь должно быть очевидно, что требование космического пространства O(N)
, Так что, если ваша строка не смешно долго, это не должно вызывать OutOfMemoryError
.
Конечно, если вы хранение сгенерированные строки - все O(2^N)
из них - в память тогда конечно ты получишь OutOfMemoryError
. Отказ Я надеюсь, что этот факт очевиден.
Вся идея Чтобы не хранить в памяти ничего, что вам не нужно генерировать этот огромный выход. Если вы тогда храните все этот огромный выход в память (вместо того, чтобы сказать, печатать их stdout
или файл), затем он побеждает все цели, и вы получите OutOfMemoryError
как и ожидалось.
Другие советы
Возможно, вы захотите рассмотреть возможность использования профилировщика, который может дать вам изображение того, какие типы объектов существуют в любой момент времени в вашей программе. В качестве одного примера NetBeans имеет встроенный профилировщик.
С тем, что было сказано, что вероятность виновника - как указывалось другими - необычайно большая память, которую ваш двумерный массив потребует в качестве гласного количества.
Я предполагаю, что у вас есть что следующий код:
int totalCombination = 1 << vowelCount;
System.out.println("totalCombination = " + totalCombination);
System.out.println("totalCombination (in Millions) = " + totalCombination / 1000 / 1000);
int[] arr = new int[totalCombination];
В 32-битной VM Array не может расти дальше 4 ГБ, это 1024 миллиона записей. Убедитесь, что вы всегда получаете меньшие числа, напечатанные в вышеуказанном коде.
И, возможно, вы должны взять совершенно другой алгоритм. Но для этого вам придется сказать нам, что вы хотите достичь, а не как Вы пытаетесь это.