Created
November 19, 2018 12:48
-
-
Save ageldama/3ff89dead5f9dce4c65b1c5a692266a1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package eu.javaspecialists.tjsn.memory; | |
| import java.lang.instrument.Instrumentation; | |
| import java.lang.reflect.*; | |
| import java.util.*; | |
| public class MemoryCounterAgent { | |
| private static Instrumentation instrumentation; | |
| /** Initializes agent */ | |
| public static void premain(String agentArgs, | |
| Instrumentation instrumentation) { | |
| MemoryCounterAgent.instrumentation = instrumentation; | |
| } | |
| /** Returns object size. */ | |
| public static long sizeOf(Object obj) { | |
| if (instrumentation == null) { | |
| throw new IllegalStateException( | |
| "Instrumentation environment not initialised."); | |
| } | |
| if (isSharedFlyweight(obj)) { | |
| return 0; | |
| } | |
| return instrumentation.getObjectSize(obj); | |
| } | |
| /** | |
| * Returns deep size of object, recursively iterating over | |
| * its fields and superclasses. | |
| */ | |
| public static long deepSizeOf(Object obj) { | |
| Map visited = new IdentityHashMap(); | |
| Stack stack = new Stack(); | |
| stack.push(obj); | |
| long result = 0; | |
| do { | |
| result += internalSizeOf(stack.pop(), stack, visited); | |
| } while (!stack.isEmpty()); | |
| return result; | |
| } | |
| /** | |
| * Returns true if this is a well-known shared flyweight. | |
| * For example, interned Strings, Booleans and Number objects | |
| */ | |
| private static boolean isSharedFlyweight(Object obj) { | |
| // optimization - all of our flyweights are Comparable | |
| if (obj instanceof Comparable) { | |
| if (obj instanceof Enum) { | |
| return true; | |
| } else if (obj instanceof String) { | |
| return (obj == ((String) obj).intern()); | |
| } else if (obj instanceof Boolean) { | |
| return (obj == Boolean.TRUE || obj == Boolean.FALSE); | |
| } else if (obj instanceof Integer) { | |
| return (obj == Integer.valueOf((Integer) obj)); | |
| } else if (obj instanceof Short) { | |
| return (obj == Short.valueOf((Short) obj)); | |
| } else if (obj instanceof Byte) { | |
| return (obj == Byte.valueOf((Byte) obj)); | |
| } else if (obj instanceof Long) { | |
| return (obj == Long.valueOf((Long) obj)); | |
| } else if (obj instanceof Character) { | |
| return (obj == Character.valueOf((Character) obj)); | |
| } | |
| } | |
| return false; | |
| } | |
| private static boolean skipObject(Object obj, Map visited) { | |
| return obj == null | |
| || visited.containsKey(obj) | |
| || isSharedFlyweight(obj); | |
| } | |
| private static long internalSizeOf( | |
| Object obj, Stack stack, Map visited) { | |
| if (skipObject(obj, visited)) { | |
| return 0; | |
| } | |
| Class clazz = obj.getClass(); | |
| if (clazz.isArray()) { | |
| addArrayElementsToStack(clazz, obj, stack); | |
| } else { | |
| // add all non-primitive fields to the stack | |
| while (clazz != null) { | |
| Field[] fields = clazz.getDeclaredFields(); | |
| for (Field field : fields) { | |
| if (!Modifier.isStatic(field.getModifiers()) | |
| && !field.getType().isPrimitive()) { | |
| field.setAccessible(true); | |
| try { | |
| stack.add(field.get(obj)); | |
| } catch (IllegalAccessException ex) { | |
| throw new RuntimeException(ex); | |
| } | |
| } | |
| } | |
| clazz = clazz.getSuperclass(); | |
| } | |
| } | |
| visited.put(obj, null); | |
| return sizeOf(obj); | |
| } | |
| private static void addArrayElementsToStack( | |
| Class clazz, Object obj, Stack stack) { | |
| if (!clazz.getComponentType().isPrimitive()) { | |
| int length = Array.getLength(obj); | |
| for (int i = 0; i < length; i++) { | |
| stack.add(Array.get(obj, i)); | |
| } | |
| } | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment