2015-10-16 5 views
8

SO answerは、-Xmx JVMフラグについていくつかを明確にしています。は、-Xmxはハードな制限ですか?

import java.util.List; 
import java.util.ArrayList; 

public class FooMain { 

    private static String memoryMsg() { 
     return String.format("%s. %s. %s" 
          , String.format("total memory is: [%d]",Runtime.getRuntime().totalMemory()) 
          , String.format("free memory is: [%d]",Runtime.getRuntime().freeMemory()) 
          , String.format("max memory is: [%d]",Runtime.getRuntime().maxMemory())); 
    } 

    public static void main(String args[]) { 
     String msg = null; 
     try { 
      System.out.println(memoryMsg()); 
      List<Object> xs = new ArrayList<>(); 
      int i = 0 ; 
      while (true) { 
       xs.add(new byte[1000]); 
       msg = String.format("%d 1k arrays added.\n%s.\n" 
            , ++i 
            , memoryMsg()); 
      } 
     } finally { 
      System.out.printf(msg); 
     } 
    } 
} 

javac FooMain.javaでそれをコンパイルします。私は次のようでした実験しようとしています。私は私が手500万バイトの最大ヒープサイズでそれを実行すると:

java -Xmx5000000 FooMain 
total memory is: [5242880]. free memory is: [4901096]. max memory is: [5767168] 
4878 1k arrays added. 
total memory is: [5767168]. free memory is: [543288]. max memory is: [5767168]. 
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded 
      at java.lang.String.toCharArray(String.java:2748) 
      at java.util.Formatter$FormatSpecifier.print(Formatter.java:3048) 
      at java.util.Formatter$FormatSpecifier.printInteger(Formatter.java:2744) 
      at java.util.Formatter$FormatSpecifier.print(Formatter.java:2702) 
      at java.util.Formatter.format(Formatter.java:2488) 
      at java.util.Formatter.format(Formatter.java:2423) 
      at java.lang.String.format(String.java:2792) 
      at FooMain.memoryMsg(FooMain.java:7) 
      at FooMain.main(FooMain.java:21) 

数字は十分に接近しているが、それらは正確にに達し終わりtotal memoryの例外を除いて(非常に正確ないないようですmax memory)。特に、それぞれ1000バイトの5368の配列は、5000000以上、または5242880バイト以上を取る必要があります。これらの数字はどのように理解されるべきですか?

これは私が使用しているJavaで、OpenJDKのソースコードを見てみると

java version "1.7.0_80" 
Java(TM) SE Runtime Environment (build 1.7.0_80-b15) 
Java HotSpot(TM) Server VM (build 24.80-b11, mixed mode) 
+0

ガベージコレクションがその間に蹴られたかもしれません... –

+1

@RobertNiestrojすべての参照が保持されているため、それはできません。 –

+1

@RobertNiestrojなぜGCedする必要がありますか?私は配列を 'List'に追加しています。参照が範囲外になることはありません。 –

答えて

5

は、-Xmxはハードリミットですか?

「ハード」とはどういう意味ですか。 「プログラムによって変更できない」という場合は「はい」を選択します。ガーベッジ・コレクターが使用するさまざまなスペースのサイズは、2の倍数の倍数です。そして、明らかに、JVMは上向きではなく下向きになります。これらの数字は理解されるべきであるどのように1000のバイト配列

を割り当て

プログラム例?

千バイトJava配列を正確1000バイトを占有しない。

  • は32ビットlengthフィールドのためのスペースを含め、オブジェクトヘッダがあります。 (通常3 x 32ビットの合計)。

  • ヒープノードは2^Nバイトの倍数で割り当てられます。(通常は2^3 == 8)


その後は、OutOfMemoryErrorを引き起こしているかの質問があります。ヒープが完全にいっぱいだからだと思うかもしれません。ただし、この場合、「GCオーバーヘッドの上限を超えました」というメッセージが表示されます。これは、JVMが、ガベージコレクタを実行している全体のCPU時間に占める割合が大きすぎることをJVMが検出し​​たことを意味します。それがGCを殺したのです...メモリ不足ではありません。

「GCオーバーヘッドの制限」の根拠は、ヒープが完全closetoなったとき、GCが頻繁に実行され、少なくメモリたびに再利用して管理することです。 GCの「死のスパイラル」に入るときは、アプリケーションがその最終的な障害点に磨きをかけるのではなく、すぐにプラグを抜く方がよいでしょう。

とにかく...これが意味することは、ヒープが一杯になったときに割り当てられているどのくらいのメモリを考え出すためのあなたのヒューリスティックは、おそらく間違っているということです。それはhere記載されている

6

、最大ヒープサイズを決定するためのロジックが非常に複雑であり、多くの変数によって決定されます。実際のヒープサイズがhotspot/src/share/vm/memory/collectorPolicy.cppに設定され、それは次のコードを使用して、入力として提供-Xmx値を使用し、それを整列:

#define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1)) 

そしてmax_alignment:

align_size_up(MaxHeapSize, max_alignment()); 

align_size_upは以下のように定義されます仮想メモリー・ページ・サイズとJVMガベージ・コレクション・カード・サイズの積です。 VMページサイズは4096バイト、カードサイズは512バイトです。これらの値を差し込むと実際のMaxHeapSizeは6324224バイトになります。これは表示されている数値とよく一致します。

注:私はJVMコードで簡単に見ましたので、私は何かを見逃している可能性がありますが、答えはあなたが見ているものを足しているようです。

1

あなたの質問はかなり今では他の人が回答されていますが、関心の外に、私は

:-)数学をやった:

この値は、複数の必要があります2 MB以上の1024

5000000は1024の倍数ではありません。私の推測では、引数は1024の倍数に切り上げられ、他の答えが確認されました。総メモリ(宣言されたヒープスペース以上)は、5767168で、5632 * 1024です。拡張されたヒープスペースに合わせて、ランタイム中に最初の5242880から拡張されました。 -Xmxは最大値を宣言しているので、必ずしもすぐに割り当てられるとは限りません。 this sourceの助けを借りて、私たちはあなたのメモリ使用量(仮定64)aproximateすることができますバイトのため

  • 4878000バイトを
  • 4878 * 24 = 117072バイト配列オーバーヘッド
  • 他の作成されたオブジェクトの数バイトと文字列
  • ガベージコレクションのために少しメモリが変動します(少なくとも、各繰り返しを作成する文字列は破棄される可能性があります)

S配列は4995072バイトを占めており(偶然にも?)、既に1024の倍数になります。しかし、他のオブジェクトのオーバーヘッドは依然として存在します。したがって、ヒープスペースは、4995072以上5767168を超える1024の倍数です。最後に空きスペースがあることを考慮すると、残りのヒープメモリとヒープ以外のメモリ使用量は228808バイトになります。

最後に空き領域の単語が最後に残されます。 JVMは、クラッシュする前に必ずしもすべてのメモリをいっぱいにするわけではありません。メモリがなくなると、ガベージコレクションが頻繁に実行されます。これが実行時全体の一定の割合を占める場合、あなたのケースで起こったthe JVM exits

関連する問題