2012-01-08 48 views
10

Tôi muốn biết bất kỳ cách đơn giản nào để truy xuất kích thước của một đối tượng java? Ngoài ra, anyway để có được kích thước của một lớp như nhà điều hành sizeof trong c + +?Có cách nào đơn giản để có được kích thước của một đối tượng java không?

+0

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

+0

bạn có thể có nhiều riêng. Bạn đang nói về kích thước trong bộ nhớ mà một đối tượng java đang sử dụng? –

+0

Xem http://stackoverflow.com/questions/757300/programatically-calculate-memory-occupied-by-a-java-object-including-objects-it – user371320

Trả lời

6

Giao diện Instrumentation có phương thức getObjectSize().

Tuy nhiên, điều này chỉ cung cấp cho bạn kích thước của đối tượng, không phải là các thành phần con của nó. Vì vậy, ví dụ, nó sẽ cho bạn biết rằng tất cả các đối tượng String có cùng kích thước.

Một vấn đề khác là kích thước của một đối tượng thực sự có thể thay đổi một cách tự phát. Ví dụ, nếu bạn nhận được mã băm nhận dạng của một đối tượng và nó tồn tại một chu trình GC, thì kích thước của nó sẽ được tăng lên (ít nhất) 4 byte để lưu trữ giá trị hashcode danh tính.


Vấn đề tìm kích thước của "đối tượng" là không thể biết được ranh giới trừu tượng của đối tượng tùy ý. Có vấn đề cho một cái gì đó thậm chí đơn giản như lớp String. (Xem xét đối tượng String tạo sử dụng substring(...) trong Java 6. Bạn có thể đối tượng char[] value như một phần của this, hoặc một phần của chuỗi ban đầu, hay cả hai? Điều này có nghĩa gì đối với các kích thước của các đối tượng tương ứng?)

Vì vậy, nó là không thể tránh khỏi rằng một cái gì đó như net.sourceforge.sizeof không thể cung cấp cho một kế toán hoàn toàn chính xác của việc sử dụng không gian.

0

Trong khi chương trình của bạn đang chạy, có một cửa sổ terminal và chạy:

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

Trong đầu ra nó mang lại số lượng và tổng kích thước của trường hợp đối tượng bằng lớp. Ví dụ: 3 72 java.util.Date có nghĩa là có 3 đối tượng Ngày trong bộ nhớ lấy 24 byte mỗi bộ nhớ. Bạn có thể cần phải đầu ra đường ống vào một tập tin hoặc một cái gì đó nếu phần liên quan cuộn đi quá nhanh.

Hoặc, cho (nhiều) cụ thể hơn, chạy:

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

Sau đó mở http://localhost:7000. Bạn có thể duyệt qua các đối tượng trên heap trong trình duyệt của bạn. Thông tin

thêm:

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

Tôi nghĩ rằng nó luôn luôn được làm tròn lên đến 8 bằng cách này, trên Sun/Oracle JVM, ngay cả khi đối tượng là 12 byte, nó sẽ mất 16 trong bộ nhớ.

3

Sử dụng lớp Unsafe từ sun.misc bạn có thể nhận được trường bù trừ. Vì vậy, xem xét các đối tượng heap liên kết theo kiến ​​trúc bộ xử lý và tính toán bù trừ trường tối đa, bạn có thể đo kích thước của một đối tượng Java. Trong ví dụ bên dưới, tôi sử dụng lớp phụ trợ UtilUnsafe để tham chiếu đến đối tượng 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

Chắc chắn có thể nhận được kích thước đối tượng, vì đối tượng của một lớp nhất định chỉ là khối bộ nhớ có kích thước cố định. Tôi đã viết đoạn mã sau để tính toán kích thước của một đối tượng. Nó cũng cung cấp một phương thức như 'sizeof' trong C++. Nó đã sẵn sàng để chạy và không phụ thuộc vào gì cả. Bạn có thể sao chép và dùng thử!

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")); 
    } 
} 
Các vấn đề liên quan