| /* |
| * 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));
|
| }
|
| }
|
| }
|
| }
|