001package org.nuxeo.runtime.javaagent;
002
003import java.lang.instrument.Instrumentation;
004import java.lang.reflect.Array;
005import java.lang.reflect.Field;
006import java.lang.reflect.Modifier;
007import java.security.AccessController;
008import java.security.PrivilegedAction;
009import java.util.IdentityHashMap;
010import java.util.Map;
011
012public class NuxeoAgent {
013
014    protected static NuxeoAgent agent = new NuxeoAgent();
015
016    protected Instrumentation instrumentation;
017
018    public static void premain(String args, Instrumentation inst) {
019        agent.instrumentation = inst;
020    }
021
022    public static void agentmain(String args, Instrumentation inst) {
023        agent.instrumentation = inst;
024    }
025
026    public long sizeOf(final Object o) {
027        return instrumentation.getObjectSize(o);
028    }
029
030    public long deepSizeOf(final Object o) {
031        if (o == null) {
032            throw new NullPointerException();
033        }
034
035        return AccessController.doPrivileged(new PrivilegedAction<Long>() {
036            @Override
037            public Long run() {
038                return new GraphSizeProfiler().visit(o);
039            }
040        });
041    }
042
043    protected class GraphSizeProfiler {
044
045        protected final Map<Object, Object> visited = new IdentityHashMap<Object, Object>();
046
047        protected long visit(Object each) {
048            if (each == null) {
049                return 0;
050            }
051            if (visited.containsKey(each)) {
052                return 0;
053            }
054            visited.put(each, each);
055            long size = instrumentation.getObjectSize(each);
056            Class<?> eachType = each.getClass();
057            if (eachType.isArray()) {
058                if (eachType.getComponentType().isPrimitive()) {
059                    return 0;
060                }
061                for (int i = 0; i < Array.getLength(each); i++) {
062                    size += visit(Array.get(each, i));
063                }
064            } else {
065                size += visit(each, eachType);
066            }
067            return size;
068        }
069
070        protected long visit(Object each, Class<?> eachType) {
071            if (eachType.equals(Object.class)) {
072                return 0;
073            }
074            long size = 0;
075            for (Field eachField : eachType.getDeclaredFields()) {
076                size += visit(each, eachField);
077            }
078            return size + visit(each, eachType.getSuperclass());
079        }
080
081        protected long visit(Object each, Field eachField) {
082            if ((eachField.getModifiers() & Modifier.STATIC) != 0) {
083                return 0;
084            }
085            if (eachField.getType().isPrimitive()) {
086                return 0;
087            }
088            boolean oldAccessible = eachField.isAccessible();
089            eachField.setAccessible(true);
090            try {
091                return visit(eachField.get(each));
092            } catch (Exception e) {
093                throw new RuntimeException("Exception trying to access field " + eachField, e);
094            } finally {
095                eachField.setAccessible(oldAccessible);
096            }
097        }
098    }
099
100}