static long dataSize(O o) { return dataSize(o, new IdentityHashMap); } static long dataSize(Object o, IdentityHashMap seen) { if (o == null || seen.containsKey(o)) return 0; seen.put(o, Boolean.TRUE); long size = 12; // HotSpot header size Class c = o.getClass(); if (c.isArray()) { size += 4; // array size field int n = Array.getLength(o); size += n * dataSize_arrayElementSize(c.getComponentType()); if (!c.getComponentType().isPrimitive()) for (int i = 0; i < n; i++) size += dataSize(Array.get(o, i), seen); } else while (c != null) { Field[] fields = c.getDeclaredFields(); for (Field field : fields) { if ((field.getModifiers() & Modifier.STATIC) != 0) continue; if (field.getType().isPrimitive()) size += dataSize_primitiveSize(field.getType()); else { size += 4; // pointer Object value = null; try { field.setAccessible(true); value = field.get(o); } catch (IllegalAccessException e) { throw new RuntimeException(e); } size += dataSize(value, seen); } } c = c.getSuperclass(); } return size; } static long dataSize_primitiveSize(Class type) { if (type == boolean.class) return 4; if (type == int.class) return 4; if (type == long.class) return 8; if (type == float.class) return 4; if (type == short.class) return 4; if (type == char.class) return 4; if (type == byte.class) return 4; if (type == double.class) return 8; throw fail("woot? " + type); } static long dataSize_arrayElementSize(Class type) { if (type == boolean.class) return 1; if (type == int.class) return 4; if (type == long.class) return 8; if (type == float.class) return 4; if (type == short.class) return 2; if (type == char.class) return 2; if (type == byte.class) return 1; if (type == double.class) return 8; ret 4; // pointers }