用 Java 计算对象的大小

我想记录一个对象为一个项目占用了多少内存(希望是以字节为单位)(我正在比较数据结构的大小) ,在 Java 中似乎没有这样做的方法。假设 C/C + + 有 sizeOf()方法,但这在 Java 中是不存在的。我尝试用 Runtime.getRuntime().freeMemory()在创建对象之前和之后记录 JVM 中的空闲内存,然后记录差异,但是它只能给出0或131304,而且没有中间值,无论结构中的元素数量如何。救命啊!

391897 次浏览

您可以使用 java.lang.instrumentation包。

它有一个方法,可以用来获得具体的实现对象大小的近似值,以及与对象相关的开销。

谢尔盖给出的答案有一个很好的例子,我会在这里转载,但你应该已经看过他的评论:

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()));
}
}

来源

看看 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));
}
}

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() { }
}