介绍两种获取JAVA对象内存大小的方法。

第一种:Instrumentation

简介:

使用java.lang.instrument 的Instrumentation来获取一个对象的内存大小。利用Instrumentation并且通过代理我们可以监测在JVM运行的程序的功能,它的原理是修改方法的字节码。

首先创建代理类

  1. package com.dingtongblog.size;
  2. import java.lang.instrument.Instrumentation;
  3.  
  4. public class ObjectSize {
  5. private static volatile Instrumentation instru;
  6.  
  7. public static void premain(String args, Instrumentation inst) {
  8. instru = inst;
  9. }
  10.  
  11. public static Long getSizeOf(Object object) {
  12. if (instru == null) {
  13. throw new IllegalStateException("Instrumentation is null");
  14. }
  15. return instru.getObjectSize(object);
  16. }
  17. }
     premain方法:JVM会首先调用这个方法。通过这个方法我们就可以把属性instru初始化化成功,通过Instrumentation的getObjectSize(Object object)方法我们就获取一个对象的大小了。
 
然后把这个类打包成jar包
首先我们要创建manifest.txt,并且增加这样的一行
  1. Premain-Classcom.dingtongblog.size.ObjectSize
这个premain-Class指定了是哪个是代理类,也就是包括了premain方法的类。
然后把ObjectSize打包成jar包
 
  1. java -cmf manifest.txt simpleSize.jar com/dingtongblog/size/ObjectSize.class

运行

然后把jar引入到工程中, 并且启动参数加入
  1. -javaagent:jarpath[=options]
在命令行中执行

  1. java -javaagent:simpleSize.jar TestMain

(当前TestMain和simpleSize.jar在同一目录下)

测试代码如下:

  1. import com.dingtongblog.size.ObjectSize;
  2. public class TestMain {
  3. public static void main(String[] args) {
  4. String a = new String(aa);
  5. System.out.println(ObjectSize.getSizeOf(a));
  6. }
  7.  
  8. }
输出24
 
我们修改参数a
String a = aa; 改成
String a = aaaa;
 
然后再运行main,还是输出24。
 
    为什么值会没有改变呢?这里虽然a指向的对象已经改变了,但是输出的值还是24没变。这是因为这个使用getSizeOf这个方法取得的对象本身的内存大小,不包含对象中属性所指向的对象的大小。在String 中一共有3个int 属性,1个数组的引用,再加上对象头占的字节数为 3 * 4 + 4 +8 = 24 ,然后24正好是8的倍数,不需要填充字节。所以直接输出24。
 
有办法可以取到一个对象完整的字节数吗?有一种思路是通过反射遍历对象中每个属性,然后调用上述的方法得到每个对象大小,把得到得对象再重复上面的过程,直到最后指向的是基本类型。直接引用这篇文章中的jar包。
 
引入包,并且启动JVM的时候加上参数

  1. -javaagent:D:\sizeofag.jar

测试代码:

  1. public class TestMain {
  2.  
  3. public static void main(String[] args) throws IllegalAccessException {
  4.  
  5. String a = new String(aa);
  6. System.out.println(SizeOfAgent.fullSizeOf(a));
  7. System.out.println(SizeOfAgent.sizeOf(a));
  8.  
  9. }

可以看到输出的结果40,24

 
40就是这个对象的完整大小。首先是前面计算的24字节+数组对象头的12个字节+两个字符字节2*2 可以得到24+12+4 =40。40是8个倍数,不需要填充字节。
 
第二种是jmap ,jhat命令
   jmap 可以输出给定的程序中堆的详情。
  1. jmap -histo <pid> (pid为当前JAVA进程的id)
例如

  1. jmap -histo 20230
这样就直接输出当前堆的详细情况,但是这样不太直观。
 
通过

  1. jmap -dump:format=b,file=<filename>

可以把java的堆以hprof 二进制格式输出到一个文件中,然后通过jhat命令来查看,jhat会生成一个页面,能比较直观的查看堆详情。但是jhat需要的内存空间为dump文件的几倍,如果dump文件比较大会遇到OOM错误,这时候可以通过MAT来浏览堆信息。

例如

  1. jmap -dump:format=b,file=d:\dump.txt
然后通过

  1. jhat filename ;

(filename为之前dump出来的文件) 会解析JAVA 堆的DUMP文件并且会启动一个web服务器,服务器的默认端口为7000,命令执行完之后就可以通过127.0.0.1:7000访问堆详情了。

  1. jhat d:\dump.txt
可以得到类似这样的页面。
 
不过通过这个方法得到的计算结果和之前用的instrumentation方法得到的结果还不一样。这个地方可能计算的方法有区别,个人觉得instrumentation的结果会比较准,但是还没找到有关的资料说明这个问题。
另外使用Jprofiler工具也可以监控内存使用的详细情况。
资料:

获取JAVA对象占用的内存大小的更多相关文章

  1. 4种方法教你如何查看java对象所占内存大小

    摘要:本文讲述4种查看java对象所占内存大小的方法 本文分享自华为云社区<查看java对象所占内存大小>,作者:xiewenci. 计算java对象所占内存大小 1.使用jdk8自带AP ...

  2. 如何获取一个Java对象所占内存大小

    新建一个maven工程 我们先在IDEA中新建一个名为ObjectSizeFetcherAgent的maven工程,如下图: 在maven项目中的pom.xml中新增一个打jar包的插件,如下: &l ...

  3. Java程序占用实际内存大小

    很多人错误的认为运行Java程序时使用-Xmx和-Xms参数指定的就是程序将会占用的内存,但是这实际上只是Java堆对象将会占用的内存.堆只是影响Java程序占用内存数量的一个因素.要更好的理解你的J ...

  4. 如何计算Java对象所占内存的大小

    [ 简单总结: 随便一个java项目,引入jar包: lucene-core-4.0.0.jar 如果是 maven项目,直接用如下依赖: <dependency> <groupId ...

  5. 复杂Java对象所占内存的大小

    我们在Java单个对象内存布局中讲解了单个简单的Java对象所占内存的大小的计算.那么这篇文章主要是讲解复杂Java对象所占内存大小的计算,我们把继承.复合的对象称为复杂对象 继承对象 class P ...

  6. Java对象的内存布局以及对象所需内存大小计算详解

    1. 内存布局 在HotSpot虚拟机中,对象的内存布局可以分为三部分:对象头(Header). 实例数据(Instance Data)和对齐填充(Padding). 1) 对象头(Header): ...

  7. 【OC底层】一个OC对象占用多少内存?

    查看一个NSObject对象占用多少内存 1.引入头文件: #import <objc/runtime.h> #import <malloc/malloc.h> 2.代码如下: ...

  8. java.lang.instrument: 一个Java对象占用多少字节?

    一.对象头包括两部分信息:Mark Word(标记字段)和 Klass Pointer(类型指针)   1. Mark Word 用于存储对象自身的运行时数据,如哈希码(HashCode).GC分代年 ...

  9. 探索一个NSObject对象占用多少内存?

    1 下面写代码测试探索NSObject的本质 Objective-C代码,底层实现其实都是C\C++代码 #import <Foundation/Foundation.h> int mai ...

随机推荐

  1. Windows下用Git下载android源码 转载

    http://my.oschina.net/jiadebin/blog/52631 1.首先你的电脑要安装好git,这个请参考git官网. 2.打开git命令窗口输入git clone http:// ...

  2. 使用Java编写并运行Spark应用程序

    我们首先提出这样一个简单的需求: 现在要分析某网站的访问日志信息,统计来自不同IP的用户访问的次数,从而通过Geo信息来获得来访用户所在国家地区分布状况.这里我拿我网站的日志记录行示例,如下所示: 1 ...

  3. c语言_帮助别人

    1. /*4.找出一个二维数组中的鞍点,即该位置上的元素在该行上最大.在该列上最小,也可能没有鞍点*/ #include<stdio.h> int main() { int i,j,max ...

  4. Android(java)学习笔记69:JDK5之后的Lock锁的概述和使用

    1. Lock锁的概述: java.util.concurrent.locks,接口Lock 首先Lock是一个接口,Lock实现提供了比使用synchronized方法 和 同步代码块更为广泛的锁定 ...

  5. struts2.1笔记01:MVC框架思想浅层理解

      1. Struts 1是全世界第一个发布的MVC框架: 它由Craig McClanahan在2001年发布,该框架一经推出,就得到了世界上Java Web开发者的拥护,经过长达6年时间的锤炼,S ...

  6. Android(java)学习笔记108:通过反射获取私有构造方法并且使用

    反射获取私有构造方法并且使用: 1.获取字节码文件.class对象:          Class c = Class.forName("cn.itcast_01.Person") ...

  7. 协议Protocol

    1.协议:是一组声明方法的集合,不能声明成员变量,作用类似于接口.           遵守此协议的类就相当于拥有了这个协议的所有方法的声明,如果父类遵守了某个协议,子类也遵守了这个协议.       ...

  8. postgresql常用SQL

    --查看数据库 select * from pg_database; --查看表空间 select * from pg_tablespace; --查看语言 select * from pg_lang ...

  9. css hack 大全 各个浏览器的css

    各个浏览器的css hack区别属性: IE6: _zoom:1; IE6/7: *zoom:1; IE6/7/8/9 :\9 各个浏览器的css hack区别规则 IE6: *html{} IE7: ...

  10. 使用C#动态生成Word文档/Excel文档的程序测试通过后,部署到IIS服务器上,不能正常使用的问题解决方案

    使用C#动态生成Word文档/Excel文档的程序功能调试.测试通过后,部署到服务器上,不能正常使用的问题解决方案: 原因: 可能asp.net程序或iis访问excel组件时权限不够(Ps:Syst ...