Java利用Instrumentation获取对象大小

阅读更多

    我之前在http://teasp.iteye.com/blog/1870871这里贴出了两种计算Java对象的方式,一种是根据虚拟机实现直接计算,另一种是通过new对象测出来实际大小。前者效率高,但是不通用,而且还是有问题的,后者正确性应该不错,但是效率低。现在又从http://www.jroller.com/maxim/entry/again_about_determining_size_of这里获得了第三种方式,通过Instrumentation计算对象大小,不过根据我的测试,这份代码应该是有bug,希望有感兴趣的童鞋能一起来研究下:

/**
 * 因为要用到java.lang.instrument.Instrumentation,
 * 本代码需要打成jar包以javaagent运行,manifest.mf文件内容如下
   Manifest-Version: 1.0
   Premain-Class: com.teasp.mem.SizeOfAgent
   Boot-Class-Path: 
   Can-Redefine-Classes: false
 * 运行方式:打包成sizeof.jar后,
 * 执行java -javaagent:sizeof.jar com.teasp.mem.SizeOfAgent
 */
public class SizeOfAgent
{
    private static Instrumentation inst;
    
    /** initializes agent */
    public static void premain(String agentArgs, Instrumentation instP) 
    {
        inst = instP;
    }

    /**
     * Returns object size without member sub-objects.
     * @param o object to get size of
     * @return object size
     */
    public static long sizeOf(Object o) 
    {
        if(inst == null) 
        {
            throw new IllegalStateException("Can not access instrumentation environment.\n" +
                            "Please check if jar file containing SizeOfAgent class is \n" +
                            "specified in the java's \"-javaagent\" command line argument.");
        }
        return inst.getObjectSize(o);
    }
                  
    /**
     * Calculates full size of object iterating over
     * its hierarchy graph.
     * @param obj object to calculate size of
     * @return object size
     */
    public static long fullSizeOf(Object obj) 
    {
        Map visited = new IdentityHashMap();
        Stack stack = new Stack();
          
        long result = internalSizeOf(obj, stack, visited);
        while (!stack.isEmpty()) 
        {
            result += internalSizeOf(stack.pop(), stack, visited);
        }
        visited.clear();
        return result;
    }               
            
    private static boolean skipObject(Object obj, Map visited) 
    {
        if (obj instanceof String) {//这个if是bug,应当去掉--teasp
            // skip interned string
            if (obj == ((String) obj).intern()) {
                return true;
            }
        }
        return (obj == null) || visited.containsKey(obj);
    }
  
    @SuppressWarnings("rawtypes")
    private static long internalSizeOf(Object obj, Stack stack, Map visited) 
    {
        if (skipObject(obj, visited))
        {
            return 0;
        }
        visited.put(obj, null);
                      
        long result = 0;
        // get size of object + primitive variables + member pointers 
        result += SizeOfAgent.sizeOf(obj);
                  
        // process all array elements
        Class clazz = obj.getClass();
        if (clazz.isArray()) 
        {
            if(clazz.getName().length() != 2) 
            {// skip primitive type array
                int length =  Array.getLength(obj);
                for (int i = 0; i < length; i++) 
                {
                    stack.add(Array.get(obj, i));
                } 
            }       
            return result;
        }
                  
        // process all fields of the object
        while (clazz != null) 
        {
            Field[] fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) 
            {
                if (!Modifier.isStatic(fields[i].getModifiers())) 
                {
                    if (fields[i].getType().isPrimitive()) 
                    {
                        continue; // skip primitive fields
                    } 
                    else 
                    {
                        fields[i].setAccessible(true);
                        try 
                        {
                            // objects to be estimated are put to stack
                            Object objectToAdd = fields[i].get(obj);
                            if (objectToAdd != null) 
                            {                        
                                stack.add(objectToAdd);
                            }
                        } 
                        catch (IllegalAccessException ex) 
                        { 
                            assert false; 
                        }
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
        return result;
    }

    static Obj4SizeofTest obj = new Obj4SizeofTest();
    public static void main(String[] args) throws Exception
    {
        System.out.println("fullSizeOf : " + fullSizeOf(new Obj4SizeofTest()));
        System.out.println("sizeOf : " + sizeOf(new Obj4SizeofTest()));
        System.out.println("sizeOf Integer: " + sizeOf(new Integer(0)));
        System.out.println("sizeOf Object: " + sizeOf(new Object()));
        
        System.out.println("fullSizeOf Son: " + fullSizeOf(new Son()));
        
        System.out.println("fullSizeOf WierdStringSon: " + fullSizeOf(new WierdStringSon()));
        System.out.println("fullSizeOf WierdString: " + fullSizeOf(new WierdString()));
        
        System.out.println("HotspotSizeof Obj4SizeofTest : " + HotspotSizeof.sizeof(new Obj4SizeofTest()));
        System.out.println("determinObjSize Obj4SizeofTest : " + HotspotSizeof.determinObjSize(Obj4SizeofTest.class));
    }
} 
  

HotspotSizeof.java见http://teasp.iteye.com/blog/1870871

 

下面是测试用到的一些类:

public class Papa
{
    int aint = 4;
    public static int bint;
//    private String str = "123";
//    private String str = new String("123");
    String str = new String(new byte[]{49,50,51});
//    private String str = new String(new char[]{49,50,51});
    int[] ints = {};
//    private int[][] intss = {{}};
    int[][] intss = {{1},{1,2}};
    
    protected float getNum()
    {
        return 4.0f;
    }
}

public class Obj4SizeofTest extends Papa implements Type
{
    int aint = 3;
    public int bint = 4;
    boolean b1 = true;
    boolean b2 = true;
    boolean b3 = true;
    boolean b4 = true;
    boolean b5 = true;
    boolean b6 = true;
    boolean b7 = true;
    boolean b8 = true;
    String str1;
    Object obj = new Papa();
    public static final byte[] bytes = {97};
    String str2 = new String(bytes);
    Integer i = new Integer(1);
    int[] is = {1,2,3};
    Object[][] objs = {{new Object(),new Object()},{new Object(),new Object()}};
        
    private static class Inner 
    {}
    
    private class Inner1
    {}
}

public class Father
{
    byte f;
}

public class Son extends Father
{
    byte s;
}

public class WierdString
{
    String str = new String(new byte[]{49,50,51});
}

public class WierdStringSon extends WierdString
{
    byte b1;
}

 

你可能感兴趣的:(Java,sizeOf,对象大小,javaagent,Instrumentation)