如何准确计算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. 关于EventBus3.0使用,你看这篇就够了

    作为一枚Android开发者,关于EventBus相信应该都听说过.要是用过就请忽略本文,本文讲得比较基础. 要是没用过,建议你花两分钟看看. 目前EventBus最新版本是3.0,本demo基于3. ...

  2. 今夜我们一起学习 Apache Shiro

    简介 Apache Shiro 是一个功能强大但又非常容易使用的 Java 安全框架,提供了认证,授权,加密以及会话管理功能.因为 Shiro 的 API 是非常容易理解的,所以使用 Shiro 你可 ...

  3. python学习笔记(unittest)

    刚刚放假回来我想很多人都还没有缓过来吧 这次介绍一个python自带的测试框架 unitest #!/usr/bin/env python # -*- coding: utf_8 -*- import ...

  4. Linux命令四

    作业一: 1) 开启Linux系统前添加一块大小为20G的SCSI硬盘 2) 开启系统,右击桌面,打开终端 安装的是命令行界面 3) 为新加的硬盘分区,一个主分区大小为10G,剩余空间给扩展分区,在扩 ...

  5. python基础之字符编码(一)

    一.什么是字符编码 计算机要想工作必须通电,也就是说‘电’驱使计算机干活,而‘电’的特性,就是高低电压(高低压即二进制数1,低电压即二进制数0),也就是说计算机只认识数字 编程的目的是让计算机干活,而 ...

  6. react-redux: counter

    store: import {createStore,applyMiddleware, compose} from "redux"; import thunk from " ...

  7. 在C / C ++中清除输入缓冲区

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

  8. 10.排序数组中和为给定值的两个数字[Find2NumbersWithGivenSum]

    [题目] 输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字.要求时间复杂度是O(n).如果有多对数字的和等于输入的数字,输出任意一对即可. 例如输入数组1 ...

  9. 深入理解java虚拟机-第六章

    第6章 类文件 6.3 Class类文件的结构 Class文件是一组以8位字节为基础单位的二进制流. Class文件格式采用一种类似C语言结构伪结构存储数据,这种伪结构中只有两种数据类型:无符号数和表 ...

  10. bzoj 2657 旅游

    Written with StackEdit. Description 到了难得的暑假,为了庆祝小白在数学考试中取得的优异成绩,小蓝决定带小白出去旅游~~ 经过一番抉择,两人决定将\(T\)国作为他们 ...