我之前在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<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) {//这个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<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;
}
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;
}