ネイティブ・イメージのオブジェクト・ヘッダー・サイズ
オブジェクト・ヘッダーはメモリー内の各オブジェクトの一部であり、オブジェクトに関するメタデータを格納し、そのサイズはJVM実装および圧縮参照などの特定のJVMオプションによって異なります。オブジェクト・ヘッダーのサイズは、特に多数の小さいオブジェクトが割り当てられている場合、Javaアプリケーションのメモリー・フットプリントに直接影響します。
Oracle GraalVMネイティブ・イメージでは、オブジェクト・ヘッダーはデフォルトで4バイトであり、HotSpotで実行する場合よりも小さくなります。
たとえば、圧縮参照を持つ64ビットのHotSpot VMでは、java.lang.Object
のインスタンスは16バイト(12バイトのヘッダーと4バイトのパディング)を消費します。Oracle GraalVMネイティブ・イメージを使用すると、同じオブジェクトは8バイトしか消費せず、メモリーを大幅に節約できます。ただし、ネイティブ・イメージの場合、オブジェクト・サイズは、使用されているガベージ・コレクタ(GC)、割り当てられたインスタンス・タイプおよび圧縮参照の状態によって大きく異なります。圧縮参照は、64ビットではなく32ビットを使用し、Oracle GraalVMではデフォルトで有効になっています。
メモリー使用量の違いを確認するには、ThreadMXBean APIを使用してスレッド割当てバイトを測定するアプリケーションの例を考えてみます:
import com.sun.management.ThreadMXBean;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
public class ObjectSize {
public static void main(String[] args) {
long threadId = Thread.currentThread().threadId();
ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
long initialValue = threadMXBean.getThreadAllocatedBytes(threadId);
int count = 12 * 1024 * 1024;
ArrayList<Object> objects = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
objects.add(new Object());
}
long allocatedBytes = threadMXBean.getThreadAllocatedBytes(threadId) - initialValue;
System.out.println("Object allocation test completed: " + objects.hashCode());
System.out.println("Thread allocated " + allocatedBytes + " bytes");
}
}
アプリケーションは数百万のオブジェクト・インスタンスを作成し、その作成時に割り当てられた合計メモリーを計算します。アプリケーションは、ArrayList
のメモリーと個々のオブジェクトの両方を含む、割り当てられた合計バイト数をレポートします。
このアプリケーションを16GBのRAMとOracle GraalVM for JDK 23を搭載したマシンで実行すると、次の結果が得られます。
圧縮参照とデフォルトのシリアルGCを使用したネイティブ・イメージ:
Object allocation test completed: -718496536
Thread allocated 150995032 bytes
この内訳は次のとおりです:
48 MB for the ArrayList
96 MB for the Objects (12 * 1024 * 1024 objects × 8 bytes)
----------------------------------------------------------
Total: 144 MB
圧縮参照とデフォルトのG1 GCを使用したHotSpot:
Object allocation test completed: -1131298887
Thread allocated 251658592 bytes
この内訳は次のとおりです:
48 MB for the ArrayList
192 MB for the Objects (12 * 1024 * 1024 objects × 16 bytes)
------------------------------------------------------------
Total: 240 MB
主な違いは、オブジェクト・ヘッダー・サイズ(4バイト・ヘッダーと12バイト・ヘッダー)です。ArrayList
のメモリー・フットプリントは、両方のVMでほぼ同じです。しかし、数百万の個々のオブジェクトのメモリーは、HotSpotのオブジェクト・ヘッダーの方が大きいため異なります。
要約すると、多数の小さいオブジェクトを扱うアプリケーションでは、ネイティブ・イメージの方がメモリー・フットプリントが小さくなる可能性があります。ネイティブ・イメージの場合、オブジェクト・ヘッダーのサイズは主に、使用されているGC、割り当てられたインスタンス・タイプおよび圧縮参照の状態によって異なります。