web-dev-qa-db-ja.com

旧世代に直接割り当てられた巨大なオブジェクトのサイズ

最近、Javaのさまざまな世代でのオブジェクトの割り当てについて読んでいます。ほとんどの場合、新しいオブジェクトはEden(Young Generationの一部)に割り当てられ、次の基準のいずれかが満たされると、OldGenerationに昇格されます。

(1)オブジェクトの年齢が保有期間のしきい値に達しました
(2)オブジェクトがEden(または)別のサバイバースペース(from)からコピーされているときに、サバイバースペース(to)がいっぱいです

ただし、オブジェクトが若い世代から昇格されるのではなく、古い世代に直接割り当てられるという特殊なケースもあります。これは、作成しようとしているオブジェクトが巨大な場合(おそらく数MB程度)に発生します。


巨大/巨大なオブジェクトのサイズ/制限を知る方法はありますか?私はG1ガベージコレクターの巨大なオブジェクトの基準を知っています。サイズ制限を知りたいだけです前または中Java 6

御時間ありがとうございます :)

21
Arkantos

HotSpot JVMが若い世代に割り当てることができるオブジェクトの最大サイズは、Edenのサイズとほぼ同じです(YoungGenから2つのサバイバースペースを引いたもの)。

これは、割り当てが大まかにどのように見えるかです。

  1. tlab_top + size <= tlab_endの場合は、スレッドローカル割り当てバッファー(TLAB)を使用します
    これが最速のパスです。割り当ては、tlab_topポインタの増分です。
  2. TLABがほぼいっぱいになっている場合は、Edenで新しいTLABを作成し、新しいTLABで再試行します。
  3. TLABの残りのスペースが十分ではないが、それでも破棄するには大きすぎる場合は、オブジェクトをEdenに直接割り当ててみてください。 Edenはすべてのスレッド間で共有されるため、Edenでの割り当ては、アトミック操作を使用したポインターの増分(eden_top + size <= eden_end)でもあります。
  4. Edenでの割り当てが失敗した場合、通常、マイナーコレクションが発生します。
  5. Young GCの後でも、Edenに十分なスペースがない場合は、Old世代に直接割り当てようとします。
27
apangin

次のフラグを使用して制限を設定できます

XX:PretenureSizeThreshold=size

デフォルト値は0です。デフォルトでは、設定しないとvalue = 0と見なされないと思います。つまり、デフォルトでは、しきい値として機能する最大値はありません。デフォルトでは、オブジェクトはGCサバイバルの数に基づいてのみ昇格されます

HotSpotバージョン

Java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

実行できるすべてのVMオプション(サポートされている)を取得するには

Java -XX:+PrintVMOptions -XX:+AggressiveOpts -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal  -version

次に、 hotspot vm option document またはリストされていない場合はgoogle特定のオプションを参照できます


byte[] array = new byte[300*1024*1024];

for(MemoryPoolMXBean memoryPoolMXBean: ManagementFactory.getMemoryPoolMXBeans()){
    System.out.println(memoryPoolMXBean.getName());
    System.out.println(memoryPoolMXBean.getUsage().getUsed());
}

出力:

$ Java -Xmx1500m -Xms1500m -Xmn500m -XX:PretenureSizeThreshold=100000000 -XX:+PrintGCDetails JVMMemoryInspection
Code Cache
393664
PS Eden Space
330301752
PS Survivor Space
0
PS Old Gen
0
PS Perm Gen
2749520
7
Jigar Joshi

JVMフラグ:

-Xms1G -Xmx1G -Xmn500m -XX:PretenureSizeThreshold = 100000000 -XX:+ PrintGCDetails

若い世代のサイズを500MBに固定すると、edenは約384MBになります。したがって、384MBを超えるオブジェクトは直接OldGenに送られ、384MB未満のオブジェクトはEden自体に割り当てられます。あなたは以下の世代の使用法を見つけることができます

byte [] array = new byte [400 * 1024 * 1024];

PSYoungGen      total 448000K, used 30720K  
    eden space 384000K, 8% used  
    from space 64000K, 0% used  
    to   space 64000K, 0% used      
 ParOldGen       total 536576K, used 409600K  
   object space 536576K, 76% used 

byte [] array = new byte [300 * 1024 * 1024];

 PSYoungGen      total 448000K, used 337920K  
  eden space 384000K, 88% used  
  from space 64000K, 0% used  
  to   space 64000K, 0% used  
 ParOldGen       total 536576K, used 0K 
  object space 536576K, **0% used** 

400MBの割り当ての場合、エデンの使用量は8%であり、古い世代の使用量は76%です。300MBの割り当ての場合、エデンの使用量は88%であり、古い世代の使用量は0%です。したがって、サイズがエデンよりも大きいすべてのオブジェクトが古い世代に直接割り当てられます。

貴重な洞察をありがとうapangin&Jigar :)
-XX:PretenureSizeThresholdはまったく考慮されていないと思います。

3
Arkantos