有没有一种简单的方法来获取java对象的大小?

我想知道检索java对象大小的任何简单方法吗? 另外,无论如何要在c ++中获得像sizeof运算符这样的类的大小?

有一个opensource java.SizeOf项目 ,它确定内存中任何Java对象的大小。

Instrumentation接口有一个getObjectSize()方法。

但是,这只会给出对象本身的大小,而不是它的组件子对象。 因此,例如,它会告诉您所有String对象的大小相同。

另一个问题是物体的大小实际上可以自发地改变。 例如,如果获得对象的标识哈希码并且它在GC循环中存活,则其大小将增加(至少)4个字节以存储标识哈希码值。


找到“对象”大小的问题在于,通用实用程序类/方法不可能确定任意对象的抽象边界在哪里。 有一些问题甚至像String类一样简单。 (考虑在Java 6中使用substring(...)创建的String对象。您是否可以将char[] value对象作为this对象的一部分,或者原始String的一部分,或两者兼而有之?这对于大小是什么意味着什么?各自的对象?)

因此,像net.sourceforge.sizeof这样的东西不可能完全准确地计算空间使用量。

使用sun.miscUnsafe类可以获得字段偏移量。 因此,根据处理器体系结构考虑对象堆对齐并计算最大字段偏移量,可以测量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 instanceFields = new LinkedList(); 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() { } } 

它绝对有可能获得对象大小,因为某个类的对象只是一个固定大小的内存块。 我编写了以下代码来计算对象的保留大小。 它还提供了一种类似C ++中’sizeof’的方法。 它是随时可用的,完全不依赖于任何东西。 你可以复制并试一试!

 public class ObjectSizer { public static final Unsafe us = getUnsafe(); public static boolean useCompressedOops = true; public static int retainedSize(Object obj) { return retainedSize(obj, new HashMap()); } private static int retainedSize(Object obj, HashMap calculated) { try { if (obj == null) throw new NullPointerException(); calculated.put(obj, obj); Class cls = obj.getClass(); if (cls.isArray()) { int arraysize = us.arrayBaseOffset(cls) + us.arrayIndexScale(cls) * Array.getLength(obj); if (!cls.getComponentType().isPrimitive()) { Object[] arr = (Object[]) obj; for (Object comp : arr) { if (comp != null && !isCalculated(calculated, comp)) arraysize += retainedSize(comp, calculated); } } return arraysize; } else { int objectsize = sizeof(cls); for (Field f : getAllNonStaticFields(obj.getClass())) { Class fcls = f.getType(); if (fcls.isPrimitive()) continue; f.setAccessible(true); Object ref = f.get(obj); if (ref != null && !isCalculated(calculated, ref)) { int referentSize = retainedSize(ref, calculated); objectsize += referentSize; } } return objectsize; } } catch (Exception e) { throw new RuntimeException(e); } } public static int sizeof(Class cls) { if (cls == null) throw new NullPointerException(); if (cls.isArray()) throw new IllegalArgumentException(); if (cls.isPrimitive()) return primsize(cls); int lastOffset = Integer.MIN_VALUE; Class lastClass = null; for (Field f : getAllNonStaticFields(cls)) { if (Modifier.isStatic(f.getModifiers())) continue; int offset = (int) us.objectFieldOffset(f); if (offset > lastOffset) { lastOffset = offset; lastClass = f.getClass(); } } if (lastOffset > 0) return modulo8(lastOffset + primsize(lastClass)); else return 16; } private static Field[] getAllNonStaticFields(Class cls) { if (cls == null) throw new NullPointerException(); List fieldList = new ArrayList(); while (cls != Object.class) { for (Field f : cls.getDeclaredFields()) { if (!Modifier.isStatic(f.getModifiers())) fieldList.add(f); } cls = cls.getSuperclass(); } Field[] fs = new Field[fieldList.size()]; fieldList.toArray(fs); return fs; } private static boolean isCalculated(HashMap calculated, Object test) { Object that = calculated.get(test); return that != null && that == test; } private static int primsize(Class cls) { if (cls == byte.class) return 1; if (cls == boolean.class) return 1; if (cls == char.class) return 2; if (cls == short.class) return 2; if (cls == int.class) return 4; if (cls == float.class) return 4; if (cls == long.class) return 8; if (cls == double.class) return 8; else return useCompressedOops ? 4 : 8; } private static int modulo8(int value) { return (value & 0x7) > 0 ? (value & ~0x7) + 8 : value; } private static Unsafe getUnsafe() { try { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe) f.get(Unsafe.class); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) { System.out.println(retainedSize("Hello Leeeeeeeen")); } } 

在程序运行时,获取另一个终端窗口并运行:

 jmap -histo  

在输出中,它按类提供对象实例的数量和总大小。 例如, 3 72 java.util.Date意味着内存中有3个Date对象,每个对象占用24个字节。 如果相关部分滚动太快,您可能需要将输出传输到文件或其他内容。

或者,对于(更多)更多细节,运行:

 jmap -dump:format=b,file=heap.bin  jhat heap.bin 

然后打开http:// localhost:7000 。 您可以在浏览器中浏览堆上的对象。

更多信息:

http://docs.oracle.com/javase/6/docs/technotes/tools/share/jmap.html
http://docs.oracle.com/javase/6/docs/technotes/tools/share/jhat.html

我认为它总是在Sun / Oracle JVM上四舍五入到8,即使对象是12个字节,它也需要16个内存。