/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.pepsoft.util; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; import java.util.Set; /** * * @author pepijn */ public class MemoryUtils { /** * Get the memory used by a particular object instance in bytes. To prevent runaway * * @param object The object of which to determine the memory used. * @param stopAt Types of references which should not be followed. * @return The number of bytes of RAM used by the object. */ public static int getSize(Object object, Set<Class<?>> stopAt) { if (object == null) { return 0; } else { IdentityHashMap<Object, Void> processedObjects = new IdentityHashMap<>(); return getSize(object, processedObjects, stopAt/*, "root"*/); } } private static int getSize(Object object, IdentityHashMap<Object, Void> processedObjects, Set<Class<?>> stopAt/*, String trail*/) { if (processedObjects.containsKey(object)) { // This object has already been counted return 0; } else { // Record that this object has been counted processedObjects.put(object, null); Class<?> type = object.getClass(); if ((stopAt != null) && (! stopAt.isEmpty())) { for (Class<?> stopClass: stopAt) { if (stopClass.isAssignableFrom(type)) { return 0; } } } int objectSize = 8; // Housekeeping if (type.isArray()) { objectSize += 4; // Array length Class<?> arrayType = type.getComponentType(); if (arrayType.isPrimitive()) { if (arrayType == boolean.class) { objectSize += ((boolean[]) object).length; } else if (arrayType == byte.class) { objectSize += ((byte[]) object).length; } else if (arrayType == char.class) { objectSize += ((char[]) object).length * 2; } else if (arrayType == short.class) { objectSize += ((short[]) object).length * 2; } else if (arrayType == int.class) { objectSize += ((int[]) object).length * 4; } else if (arrayType == float.class) { objectSize += ((float[]) object).length * 4; } else if (arrayType == long.class) { objectSize += ((long[]) object).length * 8; } else { objectSize += ((double[]) object).length * 8; } } else { Object[] array = (Object[]) object; objectSize = array.length * 4; // References for (Object anArray : array) { if (anArray != null) { objectSize += getSize(anArray, processedObjects, stopAt/*, trail + '[' + i + ']'*/); } } } } else if (type.isPrimitive()) { objectSize += PRIMITIVE_TYPE_SIZES.get(type); } else { Class<?> myType = type; while (myType != null) { Field[] fields = myType.getDeclaredFields(); for (Field field: fields) { if (Modifier.isStatic(field.getModifiers())) { continue; } Class<?> fieldType = field.getType(); if (fieldType.isPrimitive()) { objectSize += PRIMITIVE_TYPE_SIZES.get(fieldType); } else { objectSize += 4; // Reference field.setAccessible(true); // Will fail if a security manager is installed! try { Object value = field.get(object); if (value != null) { objectSize += getSize(value, processedObjects, stopAt/*, trail + '.' + field.getName()*/); } } catch (IllegalAccessException e) { throw new RuntimeException("Access denied trying to read field " + field.getName() + " of type " + myType.getName(), e); } } } myType = myType.getSuperclass(); } } if ((objectSize % 8) != 0) { objectSize = ((objectSize >> 3) + 1) << 3; } // System.out.println(trail + " (" + type.getSimpleName() + "): " + objectSize); return objectSize; } } private static final Map<Class<?>, Integer> PRIMITIVE_TYPE_SIZES = new HashMap<>(); static { PRIMITIVE_TYPE_SIZES.put(boolean.class, 1); PRIMITIVE_TYPE_SIZES.put(byte.class, 1); PRIMITIVE_TYPE_SIZES.put(char.class, 2); PRIMITIVE_TYPE_SIZES.put(short.class, 2); PRIMITIVE_TYPE_SIZES.put(int.class, 4); PRIMITIVE_TYPE_SIZES.put(float.class, 4); PRIMITIVE_TYPE_SIZES.put(long.class, 8); PRIMITIVE_TYPE_SIZES.put(double.class, 8); } }