一、前言
想知道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

java对象内存占用的更多相关文章

  1. Java 对象内存占用

    java基本类型及对象占用的内存大小 请参考下面文章 原始类型及对象占用的内存大小 http://www.javamex.com/tutorials/memory/object_memory_usag ...

  2. 一个Java对象到底占用多大内存?

    最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...

  3. 一个Java对象到底占用多大内存

    在网上搜到了一篇博客讲的非常好,里面提供的这个类也非常实用: import java.lang.instrument.Instrumentation; import java.lang.reflect ...

  4. Ehcache计算Java对象内存大小

    在EHCache中,可以设置maxBytesLocalHeap.maxBytesLocalOffHeap.maxBytesLocalDisk值,以控制Cache占用的内存.磁盘的大小(注:这里Off ...

  5. java对象内存大小评估

    Java对象的内存布局:对象头(Header).实例数据(Instance Data)和对齐填充(Padding).无论是32位还是64位的HotSpot,使用的都是8字节对齐.也就是说每个java对 ...

  6. Java对象内存模型

    2 Java对象内存模型 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header). 实例数据(Instance Data)和对齐填充(Padding). 在 JVM ...

  7. JAVA 对象内存结构

    JAVA对象内存结构 HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header).实例数据(Instance Data)和对齐填充(Padding). 对象头 markWo ...

  8. Synchronized加锁、锁升级和java对象内存结构

    首先了解一下JMM中定义的内存操作: 一个线程操作数据时候都是从主内存(堆内存)读取到自己工作内存(线程私有的数据区域)中再进行操作.对于硬件内存来说,并没有工作内存和主内存的区分,这都是java内存 ...

  9. Java对象内存布局

    本文转载自Java对象内存布局 导语 首先直接抛出问题 Unsafe.getInt(obj, fieldOffset)中的fieldOffset是什么, 类似还有compareAndSwapX(obj ...

随机推荐

  1. ios Url Encode

    //ios Url Encode //有时候在请求的参数里里特殊符号比如“+”等.而如果没有encode的话那么传过去的还是” ”,面实际上是%2B. -(NSString*)UrlValueEnco ...

  2. 老周发布 UWP 应用的隐私策略(通用)

    UWP 应用隐私策略 前注  本声明通用于老周所发布的所有 UWP 应用,下文简称“应用”.开发者全称:周家安,下文简称“老周”. 1.免责声明 您在使用应用过程中,请遵守<中华人民共和国宪法& ...

  3. javascript中IE浏览器不支持NEW DATE()带参数的解决方法

    代码如下: var date1=new Date(dateTimes[z][1]); 在火狐下 可以正常取得时间,在IE7下 却是 NaN.纠结老长时间,放弃了new date 然后再老外的论坛中找了 ...

  4. JVM类加载机制与对象的生命周期

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6536048.html  虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最 ...

  5. climbing-stairs-动态规划,爬楼梯的路径数

    You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb ...

  6. vs2017莫名自动退出调试状态可以尝试一下如下的方法

  7. APache PDFbox API使用(1)----简单介绍

    因为项目的须要.近期在学习APache  PDFbox API,Apache PDFbox API是Apache Java 开源社区中个一个项目,其受Apache 版权 V2的保护,其提供了以下的功能 ...

  8. centos6.5官方dvd做本地yum

    问题描述: 一切都搞定了,就是yum makecache 出现文件404,再目录看了也不对没后缀...(这不扯淡吗,rhel的dvd是可以直接使用的,难道企业版与社区版的区别??) 日志记录 [roo ...

  9. 分布式交易系统的并发处理, 以及用Redis和Zookeeper实现分布式锁

    交易系统 交易系统的数据结构 支付系统API通常需要一个“订单号”作为入参, 而实际调用API接口时使用到的往往不是真正意义的业务订单号, 而是交易订单号.  支付系统的API会使用“商户号+订单号” ...

  10. Ubuntu 安装asciidoc时默认推荐了巨大的安装包

    $ sudo apt-get install asciidocReading package lists... DoneBuilding dependency tree       Reading s ...