質問
大量のスレッドを生成するループがあります。これらのスレッドには、特に 2 つの (大規模な) StringBuilder オブジェクトが含まれています。これらのスレッドは実行され、本来の処理を実行します。
しかし、一定量のスレッドを実行すると、奇妙なクラッシュが発生することに気付きました。これらの StringBuilder の初期容量を減らすと、より多くのスレッドを開始できるため、これが原因であることはわかっています。これらの StringBuilder は、スレッド オブジェクトのコンストラクターで次のように作成されます。
StringBuilder a = 新しい StringBuilder(30000);
StringBuilder b = 新しい StringBuilder(30000);
通常、クラッシュするポイントは約 550 スレッドで、結果として 62MB を少し超える程度になります。プログラムの残りの部分と組み合わせると、使用されているメモリはおそらく 64MB になります。オンラインのどこかで読んだのですが、これは JVM メモリ割り当てプールのデフォルト サイズでした。これが本当かどうかはわかりません。
さて、私が何か間違ったことをしているのでしょうか、どういうわけか設計のせいで、間違った方法でメモリを割り当てているのでしょうか?それともこれが唯一の方法であり、JVM にメモリプールを増やすように指示する必要がありますか?それとも全く別の何かでしょうか?
また、より低い容量を設定するように指示しないでください。これらの StringBuilder が必要に応じて自動的に容量を増やすことはわかっていますが、この問題の解決策があれば幸いです。
解決
使用 -Xmx
Java の最大ヒープ サイズを増やすための JVM オプション。
J2SE 5.0 より前では、デフォルトの最大ヒープ サイズは 64MB でした。このデフォルトをオーバーライドするには、
-Xmx
コマンドラインオプション。
他のヒント
StringBuilder に大量の情報を保存している場合、ある時点でその情報を参照するつもりですか?そうでない場合は、別のメディア(DB、ファイルなど)に書き込んでください。プログラムのリソースは有限であり、システム全体のすべての状態を一度に保持することはできません。-Xmx を使用すると、メモリ内のストレージ領域が増えますが、ストレージ容量が無限になるわけではありません。
の使用を検討してください。 ThreadPoolExecutor
, 、プール サイズをマシン上の CPU の数に設定します。CPU よりも多くのスレッドを作成すると、オーバーヘッドが増えるだけです。
ExecutorService service = Executors.newFixedThreadPool(cpuCount))
また、文字列をメモリ内に保持するのではなく、ファイルに書き込むことでメモリ使用量を削減できます。 StringBuilder
s.
スレッドあたり 1MB を想定します。これは、それぞれを作成するための RAM コストであり、そのプロセスによって割り当てられたメモリを上回ります。
Gregory が言ったように、jvm に -Xmx などのオプションを付けてください。
また、ThreadPool または Executor を使用して、指定された量のスレッドのみが同時に実行されるようにすることも検討してください。そうすることで、速度を低下させることなくメモリ量を制限したままにすることができます (いずれにせよ、プロセッサは同時に 550 スレッドを実行する能力がないため)。
また、Executor を使用している場合は、コンストラクター内ではなく、run メソッド内で StringBuilders を作成してください。
を使用できます ファイルライター テキストをファイルに出力し、それを FileReader で取り込みます。そうすれば、文字列の内容全体ではなく、ファイル名のみをメモリに保存する必要があります。
スレッドを削減するには、ExecutorService を使用するか、単にキューから読み取るスレッドをいくつか使用します。
私の推測では、少し工夫するだけで、プログラムをメモリをほとんど必要としないレベルまで下げることができると思います。