public void initialize(long maxSharedCacheSizeInBytes) { maxCacheSizeInBytes = maxSharedCacheSizeInBytes; // Create estimators if ((maxCacheSizeInBytes > 0) && (sizeEstimators == null)) { sizeEstimators = IncrementalObjectSizeEstimator.createEstimators(SharedCache.class); } }
public static void createEstimators(Object rootObj, HashMap<Class<?>, ObjectEstimator> byType) { Deque<Object> stack = createWorkStack(rootObj, byType); continue; estimator.init(); for (Field field : getAllFields(clazz)) { Class<?> fieldClass = field.getType(); if (Modifier.isStatic(field.getModifiers())) { fieldObj = extractFieldObj(obj, field); fieldClass = determineRealClass(byType, stack, field, fieldClass, fieldObj); addArrayEstimator(byType, stack, field, fieldObj); } else if (Collection.class.isAssignableFrom(fieldClass)) { estimator.addField(FieldType.COLLECTION, field); addCollectionEstimator(byType, stack, field, fieldClass, fieldObj); } else if (Map.class.isAssignableFrom(fieldClass)) { estimator.addField(FieldType.MAP, field); addMapEstimator(byType, stack, field, fieldClass, fieldObj); } else { estimator.addField(FieldType.OTHER, field); addToProcessing(byType, stack, fieldObj, fieldClass);
public static HashMap<Class<?>, ObjectEstimator> createEstimators(Object rootObj) { HashMap<Class<?>, ObjectEstimator> byType = new HashMap<>(); addHardcodedEstimators(byType); createEstimators(rootObj, byType); return byType; }
private static Deque<Object> createWorkStack(Object rootObj, HashMap<Class<?>, ObjectEstimator> byType) { Deque<Object> stack = new ArrayDeque<Object>(32); Class<?> rootClass = rootObj.getClass(); if (Class.class.equals(rootClass)) { rootClass = (Class<?>) rootObj; rootObj = null; } else { // If root object is an array, map or collection, add estimators as for fields if (rootClass.isArray() && !rootClass.getComponentType().isPrimitive()) { addArrayEstimator(byType, stack, null, rootObj); } else if (Collection.class.isAssignableFrom(rootClass)) { addCollectionEstimator(byType, stack, null, rootClass, rootObj); } else if (Map.class.isAssignableFrom(rootClass)) { addMapEstimator(byType, stack, null, rootClass, rootObj); } } addToProcessing(byType, stack, rootObj, rootClass); return stack; }
private static void addCollectionEstimator(HashMap<Class<?>, ObjectEstimator> byType, Deque<Object> stack, Field field, Class<?> fieldClass, Object fieldObj) { Collection<?> fieldCol = null; if (fieldObj != null) { fieldCol = (Collection<?>) fieldObj; if (fieldCol.size() == 0) { fieldCol = null; LOG.trace("Empty collection {}", field); } } if (fieldCol != null) { for (Object element : fieldCol) { if (element != null) { addToProcessing(byType, stack, element, element.getClass()); } } } if (field != null) { Class<?> collectionArg = getCollectionArg(field); if (collectionArg != null) { addToProcessing(byType, stack, null, collectionArg); } // TODO: there was code here to create guess-estimate for collection wrt how usage changes // when removing elements. However it's too error-prone for anything involving // pre-allocated capacity, so it was discarded. // We will estimate collection as an object (only if it's a field). addToProcessing(byType, stack, fieldObj, fieldClass); } }
Object k = element.getKey(), v = element.getValue(); if (k != null) { addToProcessing(byType, stack, k, k.getClass()); addToProcessing(byType, stack, v, v.getClass()); Class<?>[] mapArgs = getMapArgs(field); if (mapArgs != null) { for (Class<?> mapArg : mapArgs) { addToProcessing(byType, stack, null, mapArg); addToProcessing(byType, stack, fieldObj, fieldClass);
private static Class<?> determineRealClass(HashMap<Class<?>, ObjectEstimator> byType, Deque<Object> stack, Field field, Class<?> fieldClass, Object fieldObj) { if (fieldObj == null) return fieldClass; Class<?> realFieldClass = fieldObj.getClass(); if (!fieldClass.equals(realFieldClass)) { addToProcessing(byType, stack, null, fieldClass); return realFieldClass; } return fieldClass; }
private static Deque<Object> createWorkStack(Object rootObj, HashMap<Class<?>, ObjectEstimator> byType) { Deque<Object> stack = new ArrayDeque<Object>(32); Class<?> rootClass = rootObj.getClass(); if (Class.class.equals(rootClass)) { rootClass = (Class<?>) rootObj; rootObj = null; } else { // If root object is an array, map or collection, add estimators as for fields if (rootClass.isArray() && !rootClass.getComponentType().isPrimitive()) { addArrayEstimator(byType, stack, null, rootObj); } else if (Collection.class.isAssignableFrom(rootClass)) { addCollectionEstimator(byType, stack, null, rootClass, rootObj); } else if (Map.class.isAssignableFrom(rootClass)) { addMapEstimator(byType, stack, null, rootClass, rootObj); } } addToProcessing(byType, stack, rootObj, rootClass); return stack; }
private static void addCollectionEstimator(HashMap<Class<?>, ObjectEstimator> byType, Deque<Object> stack, Field field, Class<?> fieldClass, Object fieldObj) { Collection<?> fieldCol = null; if (fieldObj != null) { fieldCol = (Collection<?>) fieldObj; if (fieldCol.size() == 0) { fieldCol = null; LOG.trace("Empty collection {}", field); } } if (fieldCol != null) { for (Object element : fieldCol) { if (element != null) { addToProcessing(byType, stack, element, element.getClass()); } } } if (field != null) { Class<?> collectionArg = getCollectionArg(field); if (collectionArg != null) { addToProcessing(byType, stack, null, collectionArg); } // TODO: there was code here to create guess-estimate for collection wrt how usage changes // when removing elements. However it's too error-prone for anything involving // pre-allocated capacity, so it was discarded. // We will estimate collection as an object (only if it's a field). addToProcessing(byType, stack, fieldObj, fieldClass); } }
Object k = element.getKey(), v = element.getValue(); if (k != null) { addToProcessing(byType, stack, k, k.getClass()); addToProcessing(byType, stack, v, v.getClass()); Class<?>[] mapArgs = getMapArgs(field); if (mapArgs != null) { for (Class<?> mapArg : mapArgs) { addToProcessing(byType, stack, null, mapArg); addToProcessing(byType, stack, fieldObj, fieldClass);
private static void addArrayEstimator(HashMap<Class<?>, ObjectEstimator> byType, Deque<Object> stack, Field field, Object fieldObj) { if (fieldObj == null) return; int arrayLen = Array.getLength(fieldObj); LOG.trace("Empty array {}", field); for (int i = 0; i < arrayLen; ++i) { Object element = Array.get(fieldObj, i); if (element != null) { addToProcessing(byType, stack, element, element.getClass()); } } Class<?> elementClass = fieldObj.getClass().getComponentType(); addToProcessing(byType, stack, null, elementClass); }
public static void createEstimators(Object rootObj, HashMap<Class<?>, ObjectEstimator> byType) { Deque<Object> stack = createWorkStack(rootObj, byType); continue; estimator.init(); for (Field field : getAllFields(clazz)) { Class<?> fieldClass = field.getType(); if (Modifier.isStatic(field.getModifiers())) { fieldObj = extractFieldObj(obj, field); fieldClass = determineRealClass(byType, stack, field, fieldClass, fieldObj); addArrayEstimator(byType, stack, field, fieldObj); } else if (Collection.class.isAssignableFrom(fieldClass)) { estimator.addField(FieldType.COLLECTION, field); addCollectionEstimator(byType, stack, field, fieldClass, fieldObj); } else if (Map.class.isAssignableFrom(fieldClass)) { estimator.addField(FieldType.MAP, field); addMapEstimator(byType, stack, field, fieldClass, fieldObj); } else { estimator.addField(FieldType.OTHER, field); addToProcessing(byType, stack, fieldObj, fieldClass);
private static ObjectEstimator getMemorySizeEstimator(Class<?> clazz) { ObjectEstimator estimator = sizeEstimators.get(clazz); if (estimator == null) { IncrementalObjectSizeEstimator.createEstimators(clazz, sizeEstimators); estimator = sizeEstimators.get(clazz); } return estimator; }
public static HashMap<Class<?>, ObjectEstimator> createEstimators(Object rootObj) { HashMap<Class<?>, ObjectEstimator> byType = new HashMap<>(); addHardcodedEstimators(byType); createEstimators(rootObj, byType); return byType; }
private static Class<?> determineRealClass(HashMap<Class<?>, ObjectEstimator> byType, Deque<Object> stack, Field field, Class<?> fieldClass, Object fieldObj) { if (fieldObj == null) return fieldClass; Class<?> realFieldClass = fieldObj.getClass(); if (!fieldClass.equals(realFieldClass)) { addToProcessing(byType, stack, null, fieldClass); return realFieldClass; } return fieldClass; }
public static void addEstimator(String className, HashMap<Class<?>, ObjectEstimator> sizeEstimators, Class<?> topClass) { Class<?> clazz = null; try { clazz = Class.forName(className); } catch (ClassNotFoundException e) { // Ignore and hope for the best. LOG.warn("Cannot find " + className); return; } IncrementalObjectSizeEstimator.createEstimators(clazz, sizeEstimators); } }
private static void addArrayEstimator(HashMap<Class<?>, ObjectEstimator> byType, Deque<Object> stack, Field field, Object fieldObj) { if (fieldObj == null) return; int arrayLen = Array.getLength(fieldObj); LOG.trace("Empty array {}", field); for (int i = 0; i < arrayLen; ++i) { Object element = Array.get(fieldObj, i); if (element != null) { addToProcessing(byType, stack, element, element.getClass()); } } Class<?> elementClass = fieldObj.getClass().getComponentType(); addToProcessing(byType, stack, null, elementClass); }
private int estimateArrayElements(HashMap<Class<?>, ObjectEstimator> parent, FieldAndType e, Object fieldObj, int len, IdentityHashMap<Object, Boolean> uniqueObjects) { int result = 0; Class<?> lastClass = e.field.getType().getComponentType(); ObjectEstimator lastEstimator = parent.get(lastClass); for (int i = 0; i < len; ++i) { Object element = Array.get(fieldObj, i); if (element == null) continue; if (null != uniqueObjects.put(element, Boolean.TRUE)) continue; Class<?> elementClass = element.getClass(); if (lastClass != elementClass) { lastClass = elementClass; lastEstimator = parent.get(lastClass); if (lastEstimator == null) { createEstimators(lastClass, parent); } lastEstimator = parent.get(lastClass); if (lastEstimator == null) { throw new AssertionError( "Don't know how to measure element " + lastClass.getName() + " from " + e.field); } } result += lastEstimator.estimate(element, parent, uniqueObjects); } return result; }
protected int estimateCollectionElements(HashMap<Class<?>, ObjectEstimator> parent, Collection<?> c, Field field, IdentityHashMap<Object, Boolean> uniqueObjects) { ObjectEstimator lastEstimator = null; Class<?> lastClass = null; int result = 0; for (Object element : c) { if (element == null) continue; if (null != uniqueObjects.put(element, Boolean.TRUE)) continue; Class<?> elementClass = element.getClass(); if (lastClass != elementClass) { lastClass = elementClass; lastEstimator = parent.get(lastClass); if (lastEstimator == null) { createEstimators(lastClass, parent); } lastEstimator = parent.get(lastClass); if (lastEstimator == null) { throw new AssertionError( "Don't know how to measure element " + lastClass.getName() + " from " + field); } } result += lastEstimator.estimate(element, parent, uniqueObjects); } return result; }
keyEstimator = parent.get(lastKeyClass); if (keyEstimator == null) { createEstimators(lastKeyClass, parent); valueEstimator = parent.get(lastValueClass); if (valueEstimator == null) { createEstimators(lastValueClass, parent);