Java利用Instrumentation获取对象大小升级版

    之前发过一个Java利用Instrumentation获取对象大小的博客,这次修复了一些Bug,应该是非常准确了,除了一种情况,那就是下面代码里面main方法里的情况:

/**
 * 因为要用到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 Map<Object, Object> visited = new IdentityHashMap<Object, Object>();
    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<Object, Object> visited = new IdentityHashMap<Object, Object>();
        Stack<Object> stack = new Stack<Object>();
          
        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<Object, Object> visited*/) 
    {
//        if (obj instanceof String) {
//            // 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<Object> stack/*, Map<Object, Object> 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;
    }

    public static void main(String[] args) throws Exception
    {
        Object a = new Object();
        Object b = a;
        System.out.println(System.identityHashCode(a) + ":" + System.identityHashCode(b));
        String stra = new String("abc");
        String strb = new String("abc");
        System.out.println("stra : " + fullSizeOf(stra)); //第一次计算时把"abc"这个常量池里面的字符串的字符数组给算进去了
        System.out.println("strb : " + fullSizeOf(strb)); //第二次计算时就不会
    }
}

 

Java中,可以使用Java的内存管理机制中的Java虚拟机(JVM)来获取对象大小。其中,一种比较简单的方法是使用Java语言提供的Instrumentation类。Instrumentation类是Java SE 6新增的一个API,它提供了一种可以动态修改已经加载类的方法。 下面是一个获取Java对象大小的示例代码: ```java import java.lang.instrument.Instrumentation; public class ObjectSizeFetcher { private static Instrumentation instrumentation; public static void premain(String args, Instrumentation instrumentation) { ObjectSizeFetcher.instrumentation = instrumentation; } public static long getObjectSize(Object object) { if (instrumentation == null) { throw new IllegalStateException("Instrumentation is not initialized"); } return instrumentation.getObjectSize(object); } } ``` 可以通过在JVM启动时指定`-javaagent`参数,加载上述代码并初始化Instrumentation类: ```bash java -javaagent:ObjectSizeFetcher.jar YourMainClass ``` 接下来,就可以在Java代码中使用`getObjectSize()`方法获取Java对象大小: ```java Object obj = new Object(); long size = ObjectSizeFetcher.getObjectSize(obj); System.out.println("Object size: " + size); ``` 需要注意的是,这种方法获取对象大小仅包括对象本身所占用的内存,不包括对象引用的其他对象占用的内存。同时,由于对象大小可能包含一些JVM内部的数据结构,因此获取大小并不一定完全准确,但可以用于比较不同对象大小
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值