如何准确计算Java对象的大小

原创文章,转载请注明:博客园aprogramer

原文链接:如何准确计算Java对象的大小

     有时,我们需要知道Java对象到底占用多少内存,有人通过连续调用两次System.gc()比较两次gc前后内存的使用量在计算java对象的大小,也有人根据Java虚拟机规范中的Java对象内存排列估算对象的大小,这两种方法或多或少都有问题,因为System.gc()并不一定促发GC,同一个类型的对象在32位与64位JVM中使用的内存会不一样,在64位虚拟机中是否开启指针压缩也会影响Java对象在内存中的大小。
 
     那么有没有一种既准确又方便的方法计算对象的大小呢?答案是肯定的。在Java 5中引入了Instrumentation类,这个类提供了计算对象内存占用量的方法;Hotspot支持instrumentation框架,其他的虚拟机也提供了类似的框架
 
使用Instrumentation类计算Java对象大小的过程如下:
  • 创建一个有premain方法的agent 类,
  • JVM在调用agent类的premain方法时会传入一个Instrumentation 对象,调用Instrumentation的getObjectSize方法
  • 把agent类打成一个jar包
  • 启动我们的应用程序,使用JVM参数指定agent jar的路径
下面以计算Object对象的大小为例,详细介绍使用Instrumentation计算对象大小的过程

1. 创建Instrumentation agent类

Instrumentation agent类有一个方法premain,声明如下:
 public static void premain(String args, Instrumentation inst) {
...
}

JVM会在应用程序运行之前调用这个方法(也就是在执行应用程序的main方法之前),JVM会在调用该方法时传入一个实现Instrumentation接口的实例,此时我们就可以调用getObjectSize()方法来计算对象的大小。例如我们要计算Object实例和自定义类型MyObject实例的大小,agent代码如下:

 package my;
import java.lang.instrument.Instrumentation; public class MyAgent {
public static void premain(String args, Instrumentation inst) {
Object obj = new Object();
System.out.println("Bytes used by Object:"+ inst.getObjectSize(obj));
System.out.println("Bytes used by MyObject:"+ inst.getObjectSize(new MyObject()));
}
public static void main(String[] args) {
System.out.println("main is over");
}
}

MyObject代码如下:

 package my;

 public class MyObject{
Object object = new Object();
}
需要注意的是agent类不需要实现任何接口,只需要定义premain方法就行,JVM会自动调用该方法。

2. 把agent类打包成jar包

在打包之前需要创建manifest 文件,创建manifest.txt文件,包括以下内容:
Premain-Class: my.MyAgent
然后执行一下命令创建jar包
jar -cmf manifest.txt agent.jar my/*

3.使用agent运行应用程序

运行应用程序,并使用javaagent命令行参数指定instrumentation agent的jar文件,加入classpath为当前目录并且main方法在com.mypackage.Main中,命令如下:
java -javaagent:agent.jar -cp . my.MyAgent

在32位机器上运行结果如下:

hadoop@32bithost:~/workspace/my/bin$ java -javaagent:agent.jar my.MyAgent
Bytes used by Object:8
Bytes used by MyObject:16
main is over

在64位机器上(不开启指针压缩)运行结果如下:

[genie.yjd@64bithost ~]$ java -XX:-UseCompressedOops -javaagent:agent.jar -cp .  my.MyAgent
Bytes used by Object:16
Bytes used by MyObject:24
main is over

在64位机器上(开启指针压缩)运行结果如下:

[genie.yjd@64bithost~]$ java -XX:+UseCompressedOops -javaagent:agent.jar -cp . my.MyAgent 
Bytes used by Object:16
Bytes used by MyObject:16
main is over

运行结果显示对于Object对象在32bit机器上占8个字节,在64bit机器上占16个字节,而对于用于一个Object类型成员的MyObject在32bit机器上占用16个字节,而在64bit机器上不开启指针压缩是占用24个字节,开启指针压缩后占用16个字节。

在应用程序中访问Instrumentation对象

在上面的例子中,我们在premain方法中计算对象的大小。可是如果我们想要在应用程序执行期间计算某个对象的大小该怎么办呢?
我们可以这样做,在premain方法中把Instrumentation对象保存在一个static引用中,然后提供一个static方法访问这个实例,代码如下:
 public class MyAgent {
private static volatile Instrumentation globalInstr;
public static void premain(String args, Instrumentation inst) {
globalInstr = inst;
}
public static long getObjectSize(Object obj) {
if (globalInstr == null)
throw new IllegalStateException("Agent not initted");
return globalInstr.getObjectSize(obj);
}
}

这样我们就可以在应用程序中调用 MyAgent.getObjectSize()来计算运行时任意实例的大小了。

深度计算对象内存使用

     注意getObjectSize方法不包括对象应用的其他对象的大小。加入对象A引用对象B,使用getObjectSize()方法计算对象A的大小时,只包括对象B引用的大小(4byte),而不是对象B的真是大小。如何深度计算对象的大小,我会在下一篇blog中详细说明。
 
 
 

如何准确计算Java对象的大小的更多相关文章

  1. 计算Java对象内存大小

    摘要 本文以如何计算Java对象占用内存大小为切入点,在讨论计算Java对象占用堆内存大小的方法的基础上,详细讨论了Java对象头格式并结合JDK源码对对象头中的协议字段做了介绍,涉及内存模型.锁原理 ...

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

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

  3. JVM —— Java 对象占用空间大小计算

    零. 为什么要知道 Java 对象占用空间大小 缓存的实现: 在设计 JVM 内缓存时(不是借助 Memcached. Redis 等), 须要知道缓存的对象是否会超过 JVM 最大堆限制, 假设会超 ...

  4. 准确计算Java中对象的大小

    由于在项目中需要大致计算一下对象的内存占用率(Hadoop中的Reduce端内存占用居高不下却又无法解释),因此深入学习了一下如何准确计算对象的大小. 使用system.gc()和java.lang. ...

  5. 两种计算Java对象大小的方法

    之前想研究一下unsafe类,碰巧在网上看到了这篇文章,觉得写得很好,就转载过来.原文出处是: http://blog.csdn.net/iter_zc/article/details/4182271 ...

  6. 如何精确地测量java对象的大小-底层instrument API

    转载: 如何精确地测量java对象的大小-底层instrument API 关于java对象的大小测量,网上有很多例子,大多数是申请一个对象后开始做GC,后对比前后的大小,不过这样,虽然说这样测量对象 ...

  7. Java对象的大小及应用类型

    基础类型数据的大小是固定的,对于非基本类型的java对象,其大小就值得商榷了.      在java中一个空Object对象的大小是8byte,这个大小只是保存堆中没有任何属性的对象的大小,看下面的语 ...

  8. java对象内存大小评估

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

  9. 如何查看java对象的大小

    有时需要查看java对象占用了多少内存(对象大小),lucene为我们提供了一个很好的工具类,操作简单,如下: int[] s = new int[1024]; System.out.println( ...

随机推荐

  1. css3 放大缩小代码

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  2. 【lightoj-1039】A Toy Company(BFS)

    The toy company "Babies Toys" has hired you to help develop educational toys. The current ...

  3. 原创:Scala学习笔记(不断更新)

    Scala是一种函数式语言和面向对象语言结合的新语言,本笔记中就零散记下学习scala的一些心得,主要侧重函数式编程方面. 1. 以递归为核心控制结构. 实现循环处理的方式有三种:goto,for/w ...

  4. React 实现 Table 的思考

    琼玖 1 年前 (写的零零散散, 包括github不怎么样) Table 是最常用展示数据的方式之一,可是一个产品中往往很多非常类似的 Table, 但是我们碰到的情况往往是 Table A 要排序, ...

  5. 一个高性能RPC框架的连接管理

    既然说连接,先对EpollServer的连接管理做个介绍吧.客户端与服务器一次conn,被封装成为Connection类在服务器进行管理. 服务器连接有三种类型,分别为: enum EnumConne ...

  6. .net 系列化与反序列化(转载)

    .net序列化及反序列化 转载自:http://www.cnblogs.com/Tim_Liu/archive/2010/11/09/1872587.html 序列化是指一个对象的实例可以被保存,保存 ...

  7. PS更换证件照颜色

    PS是我们经常使用的设计软件,在生活中使用的范围也很广,但是对于普通的用户来说,也就是平时给自己的照片美化一下,还有就是做一些证件照.今天和大家分享的是更改证件照的颜色,网上可能有很多,但是个人感觉都 ...

  8. docker -ce(社区免费版)

    Docker -ce https://www.cnblogs.com/zhangxiaoyong/p/9706392.html Docker 是世界领先的软件容器平台.开发人员利用 Docker 可以 ...

  9. LA4992 Jungle Post

    题意 PDF 分析 炸连续的比炸单独的好. 二分答案,每种炸连续的构成一些半平面,判断半平面交是否为空. 时间复杂度\(O(T n \log^2)\) 代码 这题卡常,排序的时候必须事先算出幅角,不然 ...

  10. sqlalchemy 学习(二)scoped session

    数据库设计的难点之一,是session生命周期的管理问题.sqlalchemy提供了一个简单的session管理机制,即scoped session.它采用的注册模式.所谓的注册模式,简单来说,是指在 ...