获取JAVA对象占用的内存大小

摘要:
本文介绍了两种获取Java对象内存大小的方法。使用此方法,我们可以成功初始化属性指令。使用Instrumentation的getObjectSize方法,我们可以获得对象的大小。这是因为使用getSizeOf方法获得的对象本身的内存大小不包括对象中属性所指向的对象的大小。有没有方法获取对象的完整字节数?一种想法是反映和遍历对象中的每个属性,然后调用上述方法来获得每个对象的大小。对获得的对象重复上述过程,直到它最终指向基本类型。

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

第一种:Instrumentation

简介:

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

首先创建代理类
packagecom.dingtongblog.size;
importjava.lang.instrument.Instrumentation;
 
public classObjectSize {
    private static volatileInstrumentation instru;
 
    public static voidpremain(String args, Instrumentation inst) {
        instru =inst;
    }
 
    public staticLong getSizeOf(Object object) {
        if (instru == null) {
            throw new IllegalStateException("Instrumentation is null");
        }
        returninstru.getObjectSize(object);
    }
}
premain方法:JVM会首先调用这个方法。通过这个方法我们就可以把属性instru初始化化成功,通过Instrumentation的getObjectSize(Object object)方法我们就获取一个对象的大小了。
然后把这个类打包成jar包
首先我们要创建manifest.txt,并且增加这样的一行
Premain-Class:com.dingtongblog.size.ObjectSize
这个premain-Class指定了是哪个是代理类,也就是包括了premain方法的类。
然后把ObjectSize打包成jar包
java -cmf manifest.txt simpleSize.jar com/dingtongblog/size/ObjectSize.class 

运行

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

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

测试代码如下:

importcom.dingtongblog.size.ObjectSize;
public classTestMain {
public static voidmain(String[] args) {
String a = newString(aa);
System.out.println(ObjectSize.getSizeOf(a));
}
 
}
输出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的时候加上参数
-javaagent:D:\sizeofag.jar

测试代码:

public classTestMain {
  
    public static void main(String[] args) throwsIllegalAccessException {
  
        String a = newString(aa);
        System.out.println(SizeOfAgent.fullSizeOf(a));
        System.out.println(SizeOfAgent.sizeOf(a));
  
}

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

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

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

例如

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

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

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

免责声明:文章转载自《获取JAVA对象占用的内存大小》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇winform程序实现自动升级Swift UITextView设置富文本点击, 取消一切点击事件(放大镜/复制粘贴/删除等等)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C# LINQ学习笔记一:走进LINQ的世界

本笔记摘抄自:https://www.cnblogs.com/liqingwen/p/5832322.html,记录一下学习过程以备后续查用。 LINQ 简介: 语言集成查询(LINQ)是Visual Studio 2008和.NET Framework 3.5版中引入的一项创新功能。 传统上,针对数据的查询都是以简单的字符串表示,而没有编译时类型检查或I...

C#中常用的经典文件操作方法

 C#追加文件 StreamWriter sw = File.AppendText(Server.MapPath(".")+"\\myText.txt"); sw.WriteLine("追逐理想"); sw.WriteLine("kzlll"); sw.WriteLine(".NET笔记"); sw.Flush(); sw.Close(); C#拷贝文件...

单点登陆 ---密钥

一、需求描述 现在有A系统和B系统,需要在A系统进行单点登陆到B系统。 二、B系统要做事 1、提供一个可以让A系统登陆的网址 http://localhost:8083/Account/SingleSignOn/?u=xxx&token=FB92B341DBDB59D7 其中,u为加密后的用户名,token为B系统与A系统单点登录握手密钥 2、控制...

Java多次启动相同jar程序

背景现在很多软件都支持集群部署,但是测试环境通常资源有限,所以一般通过单台机器模拟集群部署(使用不同端口,运行相同jar包),本文的目的就是通过多种方式实现此需求。 两个程序1、jar程序   ① springboot程序   ② 只包含一个main方法,用于启动程序,输出进程ID   ③ 路径:C:/demo.jar(windows) /demo.jar...

编写前程贷投标loadrunner脚本及总结

1、完成前程贷的(登录,投标) 2、所有的返回信息都用关联函数(web_reg_save_param_ex)进行关联 3、对返回信息用(strcmp)函数进行if判断 4、总结(web_reg_save_param和web_reg_save_param_ex)区别 Action() {              web_reg_save_param_ex(...

浅淡Webservice、WSDL三种服务访问的方式(附案例)

Webservice Webservice是使应用程序以与平台和编程语言无关的方式进行相互通信技术。 eg:站点提供访问的数据接口:新浪微博、淘宝。 官方解释:它是一种构建应用程序的普遍模型,可以在任何支持网络通信的操作系统中实施运行;它是一种新的web应用程序分支,是自包含、自描述、模块化的应用,可以发布、定位、通过web调用。WebService是一个...