2012-01-08 72 views
10

我想知道任何简单的方法来检索一个Java对象的大小?此外,无论如何,以获得在C++ sizeof运算符类的大小?有没有简单的方法来获取java对象的大小?

+0

http://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-determine-the-size-of-an-object – NAVEED 2012-01-08 06:44:32

+0

你可以更具体。你在谈论java对象正在使用的内存大小吗? – 2012-01-08 06:44:41

+0

参见http://stackoverflow.com/questions/757300/programatically-calculate-memory-occupied-by-a-java-object-including-objects-it – user371320 2012-01-08 06:45:53

回答

6

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

但是,这只会给你对象本身的大小,而不是它的组件子对象。举例来说,它会告诉你所有的String对象都是相同的大小。

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


发现“的对象”的大小的问题是,它是不可能的一般效用类/方法肯定知道其中的任意对象的抽象边界。即使像String类一样简单,也存在问题。 (考虑使用Java中6 substring(...)创建String对象你可以在char[] value对象的this的一部分,还是原来的字符串的一部分,或两者兼而有之?这是什么意思为相应对象的大小?)

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

0

当你的程序运行,拿到另一个终端窗口,运行:

jmap -histo <process id of the java instance you want to debug> 

在它给人的数量和类对象实例的总大小的输出。例如,3 72 java.util.Date表示在内存中有3个Date对象,每个对象需要24个字节。如果相关部分滚动太快,您可能需要将输出传输到文件或其他东西。

或者,(多)更详细,运行:

jmap -dump:format=b,file=heap.bin <processid> 
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

我认为它总是得到的方式四舍五入为8,在Sun/Oracle的JVM,即使对象是12个字节,它会内存中有16个。

3

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

确实有可能获得对象大小,因为某个类的对象只是一个固定大小的内存块。我编写了下面的代码来计算一个对象的保留大小。它还提供了一种像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<Object, Object>()); 
    } 

    private static int retainedSize(Object obj, HashMap<Object, Object> 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<Field> fieldList = new ArrayList<Field>(); 
     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<Object, Object> 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")); 
    } 
} 
相关问题