ネイティブ・イメージのオブジェクト・ヘッダー・サイズ

オブジェクト・ヘッダーはメモリー内の各オブジェクトの一部であり、オブジェクトに関するメタデータを格納し、そのサイズは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、割り当てられたインスタンス・タイプおよび圧縮参照の状態によって異なります。

その他の情報