blob: 8d703c7e6cac4db78223f90f765b5ecb85e0f135 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.ode.agents.memory;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Calendar;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Stack;
/**
* Class
*
* @author $author$
* @version $Revision$
*/
public class SizingAgent {
private static Instrumentation instrumentation;
/**
* $method$
*
* @param options options
* @param instrumentation instrumentation
*/
public static void premain(String options, Instrumentation instrumentation) {
SizingAgent.instrumentation = instrumentation;
Class[] loaded = instrumentation.getAllLoadedClasses();
}
/**
* $method$
*
* @param args args
*/
public static void main(String[] args) {
System.out.println("Size of Object: " + sizeOf(new Object()));
System.out.println("Size of direct subclass: " + sizeOf(new SizingAgent()));
System.out.println("Size of Calendar: " +
sizeOf(Calendar.getInstance()));
}
/**
* Returns object size.
*/
public static long sizeOf(Object obj) {
if (instrumentation == null) {
return 0;
}
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) {
if (instrumentation == null) {
return 0;
}
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;
}
/**
* $method$
*
* @param obj obj
* @param visited visited
*
* @return type
*/
private static boolean skipObject(Object obj, Map visited) {
return (obj == null) || visited.containsKey(obj) ||
isSharedFlyweight(obj);
}
/**
* $method$
*
* @param obj obj
* @param stack stack
* @param visited visited
*
* @return type
*/
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);
}
/**
* $method$
*
* @param clazz clazz
* @param obj obj
* @param stack stack
*/
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));
}
}
}
}