web-dev-qa-db-ja.com

Javaでオブジェクトのサイズを計算する

私はオブジェクトがプロジェクトのためにどれだけのメモリ(バイト単位で、うまくいけば)を占有したいか(私はデータ構造のサイズを比較しています)そしてこれをJavaで行う方法がないようです。おそらく、C/C++にはsizeOf()メソッドがありますが、これはJavaでは存在しません。オブジェクトを作成する前後にRuntime.getRuntime().freeMemory()を使用してJVMの空きメモリを記録してから差分を記録しようとしましたが、構造体の要素数に関係なく、0または131304しか得られず、その間は何もありません。助けてください!

137
Tyler Petrochko

Java.lang.instrumentationパッケージを使うことができます。

http://docs.Oracle.com/javase/7/docs/api/Java/lang/instrument/Instrumentation.html

オブジェクトに関連するオーバーヘッドだけでなく、オブジェクトサイズの実装固有の近似値を取得するために使用できるメソッドがあります。

Sergeyがリンクした答えは素晴らしい例を持っています。それをここで再投稿しますが、あなたはすでに彼のコメントから見たはずです:

import Java.lang.instrument.Instrumentation;

public class ObjectSizeFetcher {
    private static Instrumentation instrumentation;

    public static void premain(String args, Instrumentation inst) {
        instrumentation = inst;
    }

    public static long getObjectSize(Object o) {
        return instrumentation.getObjectSize(o);
    }
}

GetObjectSizeを使用してください。

public class C {
    private int x;
    private int y;

    public static void main(String [] args) {
        System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
    }
}

ソース:

Javaでは、オブジェクトのサイズを決定するための最良の方法は何ですか?

78
Hunter McMillen

https://github.com/DimitrisAndreou/memory-measurer Guavaはこれを内部的に使用していますが、ObjectGraphMeasurerは特別なコマンドライン引数を使用せずにそのまま使用することが特に簡単です。

import objectexplorer.ObjectGraphMeasurer;

public class Measurer {

  public static void main(String[] args) {
    Set<Integer> hashset = new HashSet<Integer>();
    Random random = new Random();
    int n = 10000;
    for (int i = 1; i <= n; i++) {
      hashset.add(random.nextInt());
    }
    System.out.println(ObjectGraphMeasurer.measure(hashset));
  }
}
74
Louis Wasserman

Java.lang.instrument.Instrumentationクラスは、Javaオブジェクトのサイズを取得するための優れた方法を提供しますが、premainを定義してJavaエージェントでプログラムを実行する必要があります。エージェントが不要で、ダミーのJarエージェントをアプリケーションに提供しなければならない場合、これは非常に退屈です。

だから私はSun.miscからUnsafeクラスを使った別の解決策を得ました。そのため、プロセッサアーキテクチャに従ってオブジェクトのヒープ配置を考慮し、最大フィールドオフセットを計算することで、Javaオブジェクトのサイズを測定できます。以下の例では、補助クラスUtilUnsafeを使用してSun.misc.Unsafeオブジェクトへの参照を取得しています。

private static final int NR_BITS = Integer.valueOf(System.getProperty("Sun.Arch.data.model"));
private static final int BYTE = 8;
private static final int Word = NR_BITS/BYTE;
private static final int MIN_SIZE = 16; 

public static int sizeOf(Class src){
    //
    // Get the instance fields of src class
    // 
    List<Field> instanceFields = new LinkedList<Field>();
    do{
        if(src == Object.class) return MIN_SIZE;
        for (Field f : src.getDeclaredFields()) {
            if((f.getModifiers() & Modifier.STATIC) == 0){
                instanceFields.add(f);
            }
        }
        src = src.getSuperclass();
    }while(instanceFields.isEmpty());
    //
    // Get the field with the maximum offset
    //  
    long maxOffset = 0;
    for (Field f : instanceFields) {
        long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f);
        if(offset > maxOffset) maxOffset = offset; 
    }
    return  (((int)maxOffset/Word) + 1)*Word; 
}
class UtilUnsafe {
    public static final Sun.misc.Unsafe UNSAFE;

    static {
        Object theUnsafe = null;
        Exception exception = null;
        try {
            Class<?> uc = Class.forName("Sun.misc.Unsafe");
            Field f = uc.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            theUnsafe = f.get(uc);
        } catch (Exception e) { exception = e; }
        UNSAFE = (Sun.misc.Unsafe) theUnsafe;
        if (UNSAFE == null) throw new Error("Could not obtain access to Sun.misc.Unsafe", exception);
    }
    private UtilUnsafe() { }
}
16
Miguel Gamboa

"Java sizeof"をGoogleで検索した結果、javaworldに Java sizeof という素晴らしい記事がありました。実際には、興味深い読み物です。

あなたの質問に答えるために、 "sizeof()"と同等のJavaはありませんが、この記事ではインスタンス化されたクラスのバイトサイズを取得する方法について説明します。

2
John