Memory Counter 본문

Programming/Java

Memory Counter

halatha 2011. 4. 8. 03:21
instrumentation interface를 이용하는 MemoryCounter의 후속 버전. 아직 jar, javaagent 사용 방법을 몰라 실행해보지는 못했음 -_-;

//	http://www.javaspecialists.eu/archive/Issue142.html
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));
			}
		}
			}
}

import eu.javaspecialists.tjsn.memory.MemoryCounterAgent;

import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class MemoryCounterAgentTest {
	public static void measureSize(Object o) {
		long memShallow = MemoryCounterAgent.sizeOf(o);
		long memDeep = MemoryCounterAgent.deepSizeOf(o);
		System.out.printf("%s, shallow=%d, deep=%d%n",
				o.getClass().getSimpleName(),
				memShallow, memDeep);
	}
	public static void main(String[] args) {
		//measureSize(new Object());
		measureSize(new HashMap());
		measureSize(new LinkedHashMap());
		measureSize(new ReentrantReadWriteLock());
		//measureSize(new byte[1000]);
		measureSize(new boolean[1000]);
		measureSize(new String("Hello World".toCharArray()));
		measureSize("Hello World");
		measureSize(10);
		measureSize(100);
		measureSize(1000);
		measureSize(new Parent());
		measureSize(new Kid());
		measureSize(Thread.State.TERMINATED);
	}

	private static class Parent {
		private int i;
		private boolean b;
		private long l;
	}

	private static class Kid extends Parent {
		private boolean b;
		private float f;
	}
}
Comments