Una buena solución genérica es usar delta de tamaño de pila. Esto implica un esfuerzo mínimo y es reutilizable entre cualquier tipo de gráfico objeto/objeto. Al crear instancias y destruir sus objetos muchas veces y recolectar basura entre ellos, y luego tomar el promedio, evita las optimizaciones de compilación y JVM que alteran los resultados y obtienen un resultado bastante preciso. Si necesita una respuesta EXACTA hasta el byte, puede que esta no sea la solución para usted, pero para todas las aplicaciones prácticas que conozco (creación de perfiles, cálculos de requisitos de memoria) funciona extremadamente bien. El siguiente código hará exactamente eso.
public class Sizeof {
public static void main(String[] args)
throws Exception {
// "warm up" all classes/methods that we are going to use:
runGC();
usedMemory();
// array to keep strong references to allocated objects:
final int count = 10000; // 10000 or so is enough for small ojects
Object[] objects = new Object[count];
long heap1 = 0;
// allocate count+1 objects, discard the first one:
for (int i = -1; i < count; ++i) {
Object object;
//// INSTANTIATE YOUR DATA HERE AND ASSIGN IT TO 'object':
object=YOUR OBJECT;
////end your code here
if (i >= 0) {
objects[i] = object;
}
else {
object = null; // discard the "warmup" object
runGC();
heap1 = usedMemory(); // take a "before" heap snapshot
}
}
runGC();
long heap2 = usedMemory(); // take an "after" heap snapshot:
final int size = Math.round(((float)(heap2 - heap1))/count);
System.out.println("'before' heap: " + heap1 +
", 'after' heap: " + heap2);
System.out.println("heap delta: " + (heap2 - heap1) +
", {" + objects[0].getClass() + "} size = " + size + " bytes");
}
// a helper method for creating Strings of desired length
// and avoiding getting tricked by String interning:
public static String createString(final int length) {
final char[] result = new char[length];
for (int i = 0; i < length; ++i) {
result[i] = (char)i;
}
return new String(result);
}
// this is our way of requesting garbage collection to be run:
// [how aggressive it is depends on the JVM to a large degree, but
// it is almost always better than a single Runtime.gc() call]
private static void runGC()
throws Exception {
// for whatever reason it helps to call Runtime.gc()
// using several method calls:
for (int r = 0; r < 4; ++r) {
_runGC();
}
}
private static void _runGC()
throws Exception {
long usedMem1 = usedMemory(), usedMem2 = Long.MAX_VALUE;
for (int i = 0; (usedMem1 < usedMem2) && (i < 1000); ++i) {
s_runtime.runFinalization();
s_runtime.gc();
Thread.currentThread().yield();
usedMem2 = usedMem1;
usedMem1 = usedMemory();
}
}
private static long usedMemory() {
return s_runtime.totalMemory() - s_runtime.freeMemory();
}
private static final Runtime s_runtime = Runtime.getRuntime();
} // end of class
No lo llamaría una estafa exacta. – Inisheer
Bueno, no es exactamente una tontería, ya que la pregunta original no proporcionó una respuesta utilizable en este contexto ... – Varkhan
Proporcionó varios. – erickson