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、(double)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]);
}
}
解決
2つの力は指数関数的に成長します。もしも vowelCount
高く、1つの配列だけで簡単に引き起こす可能性があります OutOfMemoryError
(2^32 = 4GB
).
VMの最大メモリ要件を微調整することを試みることができます(例: -Xmx512m
)、しかし、あなたのアルゴリズムが要求していることを認識してください たくさんの記憶. 。可能であれば、より良いアルゴリズムを見つけたいかもしれません。
参照してください
- ウィキペディア:指数関数的な成長
- 小麦とチェスボードの問題 - 2人の驚くほど迅速な力がどれほど成長できるかを示す有名な逸話
java
アプリケーションランチャーコマンドラインオプション- "
-Xmxn
:メモリ割り当てプールの最大サイズを指定します。」
- "
編集後:私が予想したように、あなたはすべてのバイナリの可能性に満ちた巨大な配列を生成しています。この配列全体をメモリに実際に保存する必要はほとんどありません。 「オンザフライ」の各組み合わせを生成し、0Sと1Sの「Just-in-Time」を必要とする人に送ることができます。
これはまだ指数関数的な成長であることに留意してください。 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)
スペース)、次にaを使用します 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には組み込みプロファイラーがあります。
そうは言っても、他の人が指摘しているように、原因は、母音数が増加するにつれて2次元の配列が必要とする非常に多量の記憶です。
次のコードのようなものがあると思います。
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では、アレイは4 GBを超えることはできません。つまり、1億2400万のエントリです。上記のコードに常に少数の数字が印刷されていることを確認してください。
そして、多分あなたはまったく異なるアルゴリズムを取るべきです。しかし、そのためには、あなたが達成したいことを私たちに伝えなければならないでしょう。 どうやって あなたはそれを試しています。