Calcular el tamaño del objeto en Java [duplicado]

Resuelto Tyler Petrochko asked hace 12 años • 3 respuestas

Quiero registrar cuánta memoria (en bytes, con suerte) ocupa un objeto para un proyecto (estoy comparando tamaños de estructuras de datos) y parece que no existe ningún método para hacerlo en Java. Supuestamente, C/C++ tiene sizeOf()un método, pero este no existe en Java. Intenté registrar la memoria libre en la JVM Runtime.getRuntime().freeMemory()antes y después de crear el objeto y luego registrar la diferencia, pero solo daba 0 o 131304, y nada intermedio, independientemente de la cantidad de elementos en la estructura. ¡Ayuda por favor!

Tyler Petrochko avatar Feb 21 '12 04:02 Tyler Petrochko
Aceptado

Puedes usar el java.lang.instrumentationpaquete.

Tiene un método que se puede utilizar para obtener la aproximación específica de la implementación del tamaño del objeto, así como la sobrecarga asociada con el objeto.

La respuesta que Sergey vinculó tiene un gran ejemplo, que volveré a publicar aquí, pero ya deberías haberlo visto en su comentario:

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

Usar getObjectSize:

public class C {
    private int x;
    private int y;

    public static void main(String [] args) {
        System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
    }
}

Fuente

Hunter McMillen avatar Feb 20 '2012 21:02 Hunter McMillen

Busque en https://github.com/DimitrisAndreou/memory-measurer .
Guava lo usa internamente y ObjectGraphMeasureres especialmente sencillo de usar desde el primer momento, sin ningún argumento especial de línea de comandos.

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));
  }
}
Louis Wasserman avatar Feb 20 '2012 21:02 Louis Wasserman

La java.lang.instrument.Instrumentationclase proporciona una buena manera de obtener el tamaño de un objeto Java, pero requiere que definas premainy ejecutes tu programa con un agente Java. Esto es muy aburrido cuando no necesitas ningún agente y luego tienes que proporcionar un agente Jar ficticio a tu aplicación.

Entonces obtuve una solución alternativa usando la Unsafeclase de sun.misc. Entonces, considerando la alineación del montón de objetos de acuerdo con la arquitectura del procesador y calculando el desplazamiento máximo del campo, puede medir el tamaño de un objeto Java. En el siguiente ejemplo utilizo una clase auxiliar UtilUnsafepara obtener una referencia al sun.misc.Unsafeobjeto.

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() { }
}
Miguel Gamboa avatar May 14 '2012 16:05 Miguel Gamboa