package ch.akuhn.util; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.IdentityHashMap; import java.util.Map; public class SizeOf { private static final String[] UNIT = { "bytes", "KB", "MB", "GB", "TB" }; private int size = 0; @Override public String toString() { int order = (int) ((Math.log(size) / Math.log(1024)) + 0.05); if (order == 0) return size + " bytes"; return String.format("%.2f %s (%d bytes)", 1.0 / Math.pow(1024, order) * size, UNIT[order], size); } public SizeOf(int size) { this.size = size; } public static final SizeOf deepSizeOf(Object o) { Map<Object,Object> done = new IdentityHashMap<Object,Object>(); return new SizeOf(deepSizeOf(o, done)); } private static final int deepSizeOf(Object obj, Map<Object,Object> done) { if (obj == null || isInternedString(obj) || done.containsKey(obj)) return 0; done.put(obj, null); int size = sizeOf(obj); Class<?> type = obj.getClass(); if (type.isArray()) { if (!type.getComponentType().isPrimitive()) { int len = Array.getLength(obj); for (int n = 0; n < len; n++) { Object value = Array.get(obj, n); size += deepSizeOf(value, done); } } } else { while (type != null) { for (Field f: type.getDeclaredFields()) { if (f.getType().isPrimitive()) continue; if (Modifier.isStatic(f.getModifiers())) continue; f.setAccessible(true); Object value = getField(obj, f); int sizeOf = deepSizeOf(value, done); size += sizeOf; } type = type.getSuperclass(); } } return size; } private static Object getField(Object o, Field f) { try { return f.get(o); } catch (IllegalArgumentException ex) { throw Throw.exception(ex); } catch (IllegalAccessException ex) { throw Throw.exception(ex); } } private static boolean isInternedString(Object value) { if (!(value instanceof String)) return false; String string = (String) value; return string == string.intern(); } /** * * @see http://kohlerm.blogspot.com/2008/12/how-much-memory-is-used-by-my-java.html */ public static final int sizeOf(Object o) { // Arrays of boolean, byte, char, short, int: 2 * 4 (Object header) + 4 (length-field) + sizeof(primitiveType) * length -> align result up to a multiple of 8 // Arrays of objects: 2 * 4 (Object header) + 4 (length-field) + 4 * length -> align result up to a multiple of 8 // Arrays of longs and doubles: 2 * 4 (Object header) + 4 (length-field) + 4 (dead space due to alignment restrictions) + 8 * length // java.lang.Object: 2 * 4 (Object header) // other objects: sizeofSuperClass + 8 * nrOfLongAndDoubleFields + 4 * nrOfIntFloatAndObjectFields + 2 * nrOfShortAndCharFields + 1 * nrOfByteAndBooleanFields -> align result up to a multiple of 8 if (o.getClass().isArray()) { int componentSize = sizeOfField(o.getClass().getComponentType()); return align((2 * 4) + 4 + (componentSize * Array.getLength(o))); } else { return sizeOfInstance(o.getClass()); } } private static int sizeOfInstance(Class<?> type) { if (type == Object.class) return 8; int size = sizeOfInstance(type.getSuperclass()); for (Field f: type.getDeclaredFields()) { if (Modifier.isStatic(f.getModifiers())) continue; size += sizeOfField(f.getType()); } return align(size); } private static int align(int size) { return (size % 8) == 0 ? size : size - (size % 8) + 8; } private static int sizeOfField(Class<?> type) { if (type == Boolean.TYPE) return 1; if (type == Byte.TYPE) return 1; if (type == Character.TYPE) return 2; if (type == Short.TYPE) return 2; if (type == Integer.TYPE) return 4; if (type == Long.TYPE) return 8; if (type == Float.TYPE) return 4; if (type == Double.TYPE) return 5; return 4; } public static void main(String... args) { System.out.println(new SizeOf(1)); System.out.println(new SizeOf(10)); System.out.println(new SizeOf(100)); System.out.println(new SizeOf(500)); System.out.println(new SizeOf(600)); System.out.println(new SizeOf(700)); System.out.println(new SizeOf(800)); System.out.println(new SizeOf(900)); System.out.println(new SizeOf(1000)); System.out.println(new SizeOf(10000)); System.out.println(new SizeOf(100000)); System.out.println(new SizeOf(1000000)); } }