web-dev-qa-db-ja.com

Java -Xmxで割り当てられるよりもはるかに多くのメモリを使用する

(Javaで)作成しているプロジェクトで、教授が200mを超えて使用することは許可されていないと言っています。スタックメモリを-Xmx50mで50mに制限します(絶対に確実ですが)。 、それはまだ300メートルを使用しています

私は Eclipse Memory Analyzer を実行してみましたが、26mしか報告されません

これはすべてスタック上のメモリですか?、約300のメソッド呼び出しの深さを超えることはないと確信しています(そうです、これは再帰的なDFS検索です)。つまり、すべてのスタックフレームがほぼ使い尽くされていることになります。信じがたいメガバイト。

プログラムはシングルスレッドです。メモリ使用量を削減できる可能性のある他の場所を誰かが知っていますか?また、スタックが使用しているメモリの量を確認/制限するにはどうすればよいですか?

更新:以下のJVMオプションを使用していますが、効果はありません(上によると、約300mです):-Xss104k -Xms40m -Xmx40m -XX:MaxPermSize=1k

別の更新:実際、私がそれを少し長く実行すると(これらすべてのオプションを使用)、約半分の時間で4または5秒後に突然150mに落ちます(残りの半分は落ちません)。これが本当に奇妙なのは、私のプログラムには確率論的ではない(そして私が言ったようにシングルスレッドである)ため、実行ごとに異なる動作をする必要がある理由はありません。

私が使用しているJVMと何か関係があるのでしょうか?

Java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.3) (6b27-1.12.3-0ubuntu1~10.04)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

Java -hによると、デフォルトのJVMは-serverです。-cacaoを追加してみましたが、他のすべてのオプションを使用して)わずか59mです。これで私の問題は解決すると思います。これが必要だった理由を説明してください?また、知っておくべき欠点はありますか?

もう1つの更新:カカオはサーバーに比べて本当に遅いです。これはひどいオプションです

25
dspyz

上のコマンドは、Javaアプリケーションによって使用されるメモリの総量を反映しています。これには、特に次のものが含まれます。

  • JVM自体の基本的なメモリオーバーヘッド
  • ヒープスペース(-Xmxで囲まれている)
  • 永続的な生成スペース(-XX:MaxPermSize-すべてのJVMの標準ではありません)
  • スレッドスタックスペース(スタックあたり-Xss)。スレッドの数によっては大幅に増加する可能性があります。
  • ネイティブ割り当てによって使用されるスペース(ByteBuferクラスまたはJNIを使​​用)
16
Eyal Schneider
Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss]

ここで、最大ヒープメモリは-Xmx、最小ヒープメモリは-Xms、スタックメモリは-Xssおよび-XX maxPermSizeです。

次の例は、この状況を示しています。 Tomcatを次の起動パラメーターで起動しました。

-Xmx168m -Xms168m -XX:PermSize=32m -XX:MaxPermSize=32m -Xss1m
7
amicos

-Xmxでは、ヒープサイズを構成しています。スタックサイズを設定するには、-Xssパラメータを使用します。これらの2つのパラメーターの合計は、おおよその値になります。

-Xmx150m -Xss50m

例えば。

さらに、制御する-XX:MaxPermSizeパラメータもあります。 -clientのこのパラメーターのデフォルト値は32MBで、-serverのデフォルト値は64MBです。構成に応じて、それも計算します。 PermGenスペースは次のとおりです。

永続的な生成は、クラスオブジェクトやメソッドオブジェクトなどのVM自体を反映するために使用されます。

したがって、基本的にはクラス定義や内部ストリングなど、JVMの内部データを格納します。

最後に、私はあなたが制御できない1つの部分があることを言わなければなりません、それはネイティブで使用されるメモリですJavaプロセス。Javaはプログラムです、ちょうど他と同様に、メモリも使用しますタスクマネージャでメモリ使用量を監視している場合は、プログラムのメモリ消費量とともにこのメモリも表示されます。

5
partlov

「総メモリ使用量」(LinuxランドのRSS)には、JDKヒープ(およびその他のJDK領域)と、割り当てられた「ネイティブメモリ」が含まれることに注意することが重要です。

たとえば、これらの人々は、GC間で(ネイティブメモリに関連付けられている)jaxbcontextをあまりにも多く割り当てると、余分なRAMを大量に使用する可能性があることを発見しました。もう1つの一般的なものは、close(またはGZipStreamなど)を呼び出さない場合のZipInflaterです。

http://sleeplessinslc.blogspot.com/2014/08/jvm-native-memory-leak.html

彼の最後の回避策/修正は、GCを「より頻繁に」(GC1ガベージコレクターを使用するか、smaller[皮肉なことに] -Xmx設定を指定して)、またはJaxBContextオブジェクトをキャッシュする(オブジェクトにはcloseメソッドがないため、リークを制御できないため)。

また、jstackを調べるだけでメモリの原因を見つけることができる場合もあります。 http://javaeesupportpatterns.blogspot.com/2011/09/jaxbcontext-performance-problem-case.html

また、たとえばGZipStreamsを誤って閉じるのを「ミス」する可能性もあります http://kohsuke.org/2011/11/03/quiz-time-memory-leak-in-Java

3
rogerdpack

JVisualVMを使用してみましたか?

http://docs.Oracle.com/javase/6/docs/technotes/tools/share/jvisualvm.html

これを追跡するのに役立つことがよくあります。各種類のメモリがどの程度使用されているかが表示され、ドリルダウンして何を見つけることもできます。

1
danpaq