java对象内存占用
一、前言
想知道java对象在内存中的占用情况吗?感谢这位大神的无私分享。
http://yueyemaitian.iteye.com/blog/2033046
二、原文的扩充
1. 增加了代理jar包的打包脚本及过程
2. 增加了测试脚本的示例
三、查看字节工具类
import java.lang.instrument.Instrumentation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; import java.util.Set; /** * 对象占用字节大小工具类 * * @author tianmai.fh * @date 2014-03-18 11:29 */ public class SizeOfObject { static Instrumentation inst; public static void premain(String args, Instrumentation instP) { inst = instP; } /** * 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、<br> * </br> * 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;<br> * </br> * 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小 <br> * </br> * * @param obj * @return */ public static long sizeOf(Object obj) { return inst.getObjectSize(obj); } /** * 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小 * * @param objP * @return * @throws IllegalAccessException */ public static long fullSizeOf(Object objP) throws IllegalAccessException { Set<Object> visited = new HashSet<Object>(); Deque<Object> toBeQueue = new ArrayDeque<>(); toBeQueue.add(objP); long size = 0L; while (toBeQueue.size() > 0) { Object obj = toBeQueue.poll(); // sizeOf的时候已经计基本类型和引用的长度,包括数组 size += skipObject(visited, obj) ? 0L : sizeOf(obj); Class<?> tmpObjClass = obj.getClass(); if (tmpObjClass.isArray()) { // [I , [F 基本类型名字长度是2 if (tmpObjClass.getName().length() > 2) { for (int i = 0, len = Array.getLength(obj); i < len; i++) { Object tmp = Array.get(obj, i); if (tmp != null) { // 非基本类型需要深度遍历其对象 toBeQueue.add(Array.get(obj, i)); } } } } else { while (tmpObjClass != null) { Field[] fields = tmpObjClass.getDeclaredFields(); for (Field field : fields) { if (Modifier.isStatic(field.getModifiers()) // 静态不计 || field.getType().isPrimitive()) { // 基本类型不重复计 continue; } field.setAccessible(true); Object fieldValue = field.get(obj); if (fieldValue == null) { continue; } toBeQueue.add(fieldValue); } tmpObjClass = tmpObjClass.getSuperclass(); } } } return size; } /** * String.intern的对象不计;计算过的不计,也避免死循环 * * @param visited * @param obj * @return */ static boolean skipObject(Set<Object> visited, Object obj) { if (obj instanceof String && obj == ((String) obj).intern()) { return true; } return visited.contains(obj); } }
四、打成工具类jar包
1. 编译class文件
javac -encoding utf8 com/your/package/SizeOfObject.java
2. 编写menifest文件
Premain-class: com.your.package.SizeOfObject Can-Redefine-Classes: false Boot-Class-Path:
3. 打包
jar -cmf manifest agent.jar com/your/package/SizeOfObject.class
3.1 manifest在当前目录下
3.2 agent.jar为生成的jar包名称
3.3 class为步骤1编译成的文件
五、测试类文件
import static com.tuniu.study.SizeOfObject.fullSizeOf; import static com.tuniu.study.SizeOfObject.sizeOf; /** * @author tianmai.fh * @date 2014-03-18 20:17 */ public class SizeOfObjectTest { /** * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 = 16 * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + padding/4 = 24 */ static class A { int a; } /** * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24 * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + 4 = 24 */ static class B { int a; int b; } /** * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24 * -XX:-UseCompressedOops: mark/8 + metedata/8 + 8 + 4 + padding/4 = 32 */ static class B2 { int b2a; Integer b2b; } /** * 不考虑对象头: * 4 + 4 + 4 * 3 + 3 * sizeOf(B) */ static class C extends A { int ba; B[] as = new B[3]; C() { for (int i = 0; i < as.length; i++) { as[i] = new B(); } } } static class D extends B { int da; Integer[] di = new Integer[3]; } /** * 会算上A的实例字段 */ static class E extends A { int ea; int eb; } static class F { String s; } static class F1 { String s = "1"; } static class F2 { String s = "12"; } static class F3 { String s = "12345678"; } public static void main(String[] args) throws IllegalAccessException { System.out.println("sizeOf(new Object())=" + sizeOf(new Object())); System.out.println("sizeOf(new A())=" + sizeOf(new A())); System.out.println("sizeOf(new B())=" + sizeOf(new B())); System.out.println("sizeOf(new B2())=" + sizeOf(new B2())); System.out.println("sizeOf(new B[3])=" + sizeOf(new B[3])); System.out.println("sizeOf(new C())=" + sizeOf(new C())); System.out.println("fullSizeOf(new C())=" + fullSizeOf(new C())); System.out.println("sizeOf(new D())=" + sizeOf(new D())); System.out.println("fullSizeOf(new D())=" + fullSizeOf(new D())); System.out.println("sizeOf(new int[3])=" + sizeOf(new int[3])); System.out.println("sizeOf(new Integer(1)=" + sizeOf(new Integer(1))); System.out.println("sizeOf(new Integer[0])=" + sizeOf(new Integer[0])); System.out.println("sizeOf(new Integer[1])=" + sizeOf(new Integer[1])); System.out.println("sizeOf(new Integer[2])=" + sizeOf(new Integer[2])); System.out.println("sizeOf(new Integer[3])=" + sizeOf(new Integer[3])); System.out.println("sizeOf(new Integer[4])=" + sizeOf(new Integer[4])); System.out.println("sizeOf(new A[3])=" + sizeOf(new A[3])); System.out.println("sizeOf(new E())=" + sizeOf(new E())); System.out.println("sizeOf(new F())=" + sizeOf(new F())); System.out.println("fullSizeOf(new F())=" + fullSizeOf(new F())); System.out.println("fullSizeOf(new F1())=" + fullSizeOf(new F1())); System.out.println("fullSizeOf(new F2())=" + fullSizeOf(new F2())); System.out.println("fullSizeOf(new F3())=" + fullSizeOf(new F3())); String s = ""; System.out.println("sizeOf(s)=" + sizeOf(s)); System.out.println("fullSizeOf(s)=" + fullSizeOf(s)); s = "1"; System.out.println("sizeOf(s)=" + sizeOf(s)); System.out.println("fullSizeOf(s)=" + fullSizeOf(s)); char c = '0'; System.out.println("sizeOf(c)=" + sizeOf(c)); System.out.println("fullSizeOf(c)=" + fullSizeOf(c)); char[] cs = new char[] {}; System.out.println("sizeOf(cs)=" + sizeOf(cs)); System.out.println("fullSizeOf(cs)=" + fullSizeOf(cs)); cs = new char[] {'0','1'}; System.out.println("sizeOf(cs)=" + sizeOf(cs)); System.out.println("fullSizeOf(cs)=" + fullSizeOf(cs)); int i = 0; System.out.println("sizeOf(i)=" + sizeOf(i)); System.out.println("fullSizeOf(i)=" + fullSizeOf(i)); i = 1000000; System.out.println("sizeOf(i)=" + sizeOf(i)); System.out.println("fullSizeOf(i)=" + fullSizeOf(i)); } }
打包成可执行jar包。(我用的eclipse...export...轻松愉快)
六、运行测试
1. 运行命令
java -javaagent:sizeOf_lib/agent.jar -jar sizeOf.jar
2. 运行结果
sizeOf(new Object())=16 sizeOf(new A())=16 sizeOf(new B())=24 sizeOf(new B2())=24 sizeOf(new B[3])=32 sizeOf(new C())=24 fullSizeOf(new C())=128 sizeOf(new D())=32 fullSizeOf(new D())=64 sizeOf(new int[3])=32 sizeOf(new Integer(1)=16 sizeOf(new Integer[0])=16 sizeOf(new Integer[1])=24 sizeOf(new Integer[2])=24 sizeOf(new Integer[3])=32 sizeOf(new Integer[4])=32 sizeOf(new A[3])=32 sizeOf(new E())=24 sizeOf(new F())=16 fullSizeOf(new F())=16 fullSizeOf(new F1())=40 fullSizeOf(new F2())=40 fullSizeOf(new F3())=48 sizeOf(s)=24 fullSizeOf(s)=16 sizeOf(s)=24 fullSizeOf(s)=24 sizeOf(c)=16 fullSizeOf(c)=16 sizeOf(cs)=16 fullSizeOf(cs)=16 sizeOf(cs)=24 fullSizeOf(cs)=24 sizeOf(i)=16 fullSizeOf(i)=16 sizeOf(i)=16 fullSizeOf(i)=16
上善若水,水利万物而不争。