Java对象内存计算的几种方法

使用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;
}

}

arthinking wechat
欢迎关注itzhai公众号