计算Java中Object的大小

Tyl*_*hko 149 java memory memory-management data-structures

我想记录一个对象占用多少内存(以字节为单位)(我正在比较数据结构的大小),似乎没有方法可以在Java中执行此操作.据说,C/C++有sizeOf()方法,但这在Java中是不存在的.我尝试Runtime.getRuntime().freeMemory()在创建对象之前和之后记录JVM中的空闲内存,然后记录差异,但它只会给出0或131304,而不管结构中的元素数量是什么.请帮忙!

Hun*_*len 84

你可以使用这个java.lang.instrumentation包:

http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/Instrumentation.html

它有一个方法可用于获取对象大小的实现特定近似值,以及与对象相关的开销.

谢尔盖联系的答案有一个很好的例子,我将在此重新发布,但你应该从他的评论中看到:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用getObjectSize:

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

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

资源:

在Java中,确定对象大小的最佳方法是什么?

  • 不知道这个答案如何获得如此多的赞成.它完全忽略了必须编译一个代理类以作为参数传递给JVM的事实.不这样做会使检测为null,并触发NullPointerException.这是正确答案:http://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-determine-the-size-of-an-object (83认同)
  • 使用您尝试的内容编辑上面的帖子. (2认同)

Lou*_*man 76

查看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));
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我怀疑最常见的SO用户来这里拖延 - 所以当然我们都在这里_所有时间,_我们立即回复评论. (5认同)
  • 我以前用过内存测量器,是的。(我为 Guava 做出了贡献,并且我确实提到过我们在内部使用它。;)) (2认同)
  • 这取决于您的 JVM。如果您想测量字节,那么您应该使用同一项目中的“MemoryMeasurer”;按照那里的说明进行操作。 (2认同)

Mig*_*boa 16

java.lang.instrument.Instrumentation类提供了一个很好的方式来获得一个Java对象的大小,但它需要你定义一个premain与一个Java代理运行程序.当您不需要任何代理时,这非常无聊,然后您必须为您的应用程序提供虚拟Jar代理.

所以我得到了另一种使用Unsafe该类的替代解决方案sun.misc.因此,根据处理器体系结构考虑对象堆对齐并计算最大字段偏移量,您可以测量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() { }
}
Run Code Online (Sandbox Code Playgroud)