Java对象内存计算的几种方法
本文由发表于3年前 | J2EE | 评论数 1 |  被围观 6,907 views+

使用system.gc()和java.lang.Runtime类中的freeMemory(),totalMemory(),maxMemory()这几个方法测量Java对象的大小。这种方法通常使用在需要对很多资源进行精确确定对象的大小。这种方法几乎无用等生产系统缓存的实现。这种方法的优点是数据类型大小无关的,不同的操作系统,都可以得到占用的内存。

一个更加好的方法是:http://www.javaspecialists.co.za/archive/Issue078.html。

它使用反射API用于遍历对象的成员变量的层次结构和计算所有原始变量的大小。这种方法不需要如此多的资源,可用于缓存的实现。缺点是原始类型大小是不同的不同的JVM实现对应有不同的计算方法。

JDK5.0之后Instrumentation API提供了 getObjectSize方法来计算对象占用的内存大小。

这篇文章有介绍其实现:

http://www.jroller.com/maxim/entry/again_about_determining_size_of

默认情况下并没有计算到引用对象的大小,为了计算引用对象,可以使用反射获取。下面这个方法是上面文章里面提供的一个计算包含引用对象大小的实现:

/**
 *  Instrumentation agent used 
 *  from : http://www.jroller.com/maxim/entry/again_about_determining_size_of
 */
public class SizeOfAgent {

    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) // skip visited object
                || visited.containsKey(obj);
    }

    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;
    }
}
除了文章中有特别说明,均为IT宅原创文章,转载请以链接形式注明出处。
本文链接:http://www.itzhai.com/java-object-memory-calculate-method.html
关键字: , ,
arthinking Java技术交流群:280755654,入门群:428693174 more
分享到:
 
2014 6/8
如果您有更好的原创技术博文或者观点,欢迎投稿:admin@itzhai.com,或者关注订阅左侧浮动面板的微信号订阅IT宅itread)发送消息。
文章评论
    一条评论
给我留言

有人回复时邮件通知我
J2EE的相关文章
随机文章 本月热门 热评
1 追逐梦想的步伐 SMART目标和实用投资计划(PIP) 2012/8/4
2 C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 2011/8/30
3 Javascript中加号运算符的二义性注意事项 2012/4/28
4 关于学习新技术的方法和让自己不断进步的一点建议 2011/5/27
5 Java动态代理之JDK动态代理和CGLib动态代理 面向切面编程AOP原理 2014/4/1
6 jQuery中使用Ajax获取JSON格式数据 2011/5/17
友情推荐 更多
破博客 文官洗碗安天下,武将打怪定乾坤。多么美好的年代,思之令人泪落。
Mr.5's Life 白天是一名程序员,晚上就是个有抱负的探索者
行知-追寻技术之美 关注大数据,分布式系统
我爱编程 编程成长轨迹
Cynthia's Blog 学习笔记 知识总结 思考感悟
 
猜您喜欢
欢迎关注我的公众号 IT宅
关于IT宅 文章归档

IT宅中的文章除了标题注明转载或有特别说明的文章,均为IT宅的技术知识总结,学习笔记或随笔。如果喜欢,请使用文章下面提供的分享组件。转载请注明出处并加入文章的原链接。 感谢大家的支持。

联系我们:admin@itzhai.com

Theme by arthinking. Copyright © 2011-2015 IT宅.com 保留所有权利.