2012-01-08 46 views
10

Me gustaría saber cualquier forma simple de recuperar el tamaño de un objeto java? Además, de todos modos para obtener el tamaño de una clase como el operador sizeof en C++?¿Hay una manera simple de obtener el tamaño de un objeto Java?

+0

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

+0

puede ser más específico. ¿Estás hablando del tamaño en memoria que está usando un objeto java? –

+0

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

Respuesta

6

La interfaz Instrumentation tiene un método getObjectSize().

Sin embargo, esto solo le proporciona el tamaño del objeto en sí, no sus subobjetos componentes. Entonces, por ejemplo, le dirá que todos los objetos String son del mismo tamaño.

Otro problema es que el tamaño de un objeto en realidad puede cambiar espontáneamente. Por ejemplo, si obtiene el código hash de identidad de un objeto y sobrevive a un ciclo GC, entonces su tamaño se incrementará en (al menos) 4 bytes para almacenar el valor del código hash de identidad.


El problema de encontrar el tamaño de "un objeto" es que es imposible que una clase de utilidad/método general de saber con certeza dónde están los límites de abstracción de un objeto arbitrario son. Hay problemas para algo incluso tan simple como la clase String. (Considere objetos String creados con substring(...) en Java 6. Hacer que el objeto podría char[] value como parte de this, o parte de la cadena original, o ambas cosas? ¿Qué significa esto para los tamaños de los objetos respectivos?)

Por lo tanto, es inevitable que algo como net.sourceforge.sizeof no pueda dar una explicación completamente precisa del uso del espacio.

0

Mientras que el programa se está ejecutando, obtener otra ventana de terminal y ejecutar:

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

En la salida que da el número y el tamaño total de instancias de objetos por clase. Por ejemplo, 3 72 java.util.Date significa que hay 3 objetos de fecha en la memoria que toman 24 bytes cada uno. Es posible que necesite conectar la salida a un archivo o algo si la parte relevante se desplaza demasiado rápido.

O, por (mucho) más detalle, ejecute:

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

Entonces abierta http://localhost:7000. Puede navegar a través de los objetos en el montón en su navegador.

Más información:

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

Creo que siempre se redondea al 8 por cierto, en el Sun/Oracle JVM, incluso si el objeto es de 12 bytes, que se llevará 16 en memoria.

3

Utilizando la clase Unsafe del sun.misc puede obtener el desplazamiento de los campos. Por lo tanto, teniendo en cuenta la alineación del montón de objetos de acuerdo con la arquitectura del procesador y el cálculo del desplazamiento de campo máximo, puede medir el tamaño de un objeto de Java. En el siguiente ejemplo, utilizo una clase auxiliar UtilUnsafe para obtener una referencia al objeto 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

Es definitivamente posible conseguir el tamaño del objeto, porque un objeto de cierta clase es sólo un bloque de memoria-fix tamaño. Escribí el siguiente código para calcular el tamaño retenido de un objeto. También proporciona un método como 'sizeof' en C++. Está listo para funcionar y no depende de nada. ¡Puedes copiarlo y probarlo!

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")); 
    } 
} 
Cuestiones relacionadas