`

使用SizeOf测定JVM中对象占用内存

 
阅读更多

一、前言

最近在学习JVM相关知识时突然想到个问题:

应该如何知道自己程序中创建的对象在虚拟机中到底占用了多大的内存?

另外,各种数据类型在虚拟机中各自占用多少内存呢?

就这2个问题,上网查了一些相关的资料。

关于查看对象占用内存的方法,比较常用应该算是使用Java VisualVM工具heap dump后查看对象实例所占用的内存。

本文将采用另外一种方式,使用一个开源工具SizeOf。

二、SizeOf

1、简介

项目下载地址:http://sourceforge.net/projects/sizeof/

其实就一个jar包,放到Eclipse工程路径下,添加到classpath中。

运行前添加VM参数:-javaagent:./lib/SizeOf.jar 运行即可(将jar放在lib路径下)。

2、实现原理

下载一份源代码后发现工具类只有一个SizeOf.java。

看了一下内部实现,主要使用的是JDK1.5中提供的新功能:Instrumentation。

Instrumentation介绍(源自网络):开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在JVM上的程序,甚至能够替换和修改某些类的定义。开发者就可以实现更为灵活的运行时虚拟机监控和Java类操作,这样的特性实际上提供了一种虚拟机级别支持的AOP实现方式,使得开发者无需对JDK做任何升级和改动,就可以实现某些AOP的功能了。

在SizeOf中,其实是使用Instrumentation特性getObjectSize监控JVM程序中对象的大小。

三、验证对象占用内存大小

1、规范

首先参考JVM规范相关介绍,Java中各数据类型占用内存为:

byte:1字节

boolean:1字节(待定)

short:2字节

char:2字节

int:4字节

float:4字节

long:8字节

double:8字节

java.lang.Object:8字节

ref object:对象的引用4字节

return address:4字节

2、通过SizeOf验证

环境:Windows + Sun HotSpot VM

(1)常见的类型

System.out.println("Integer: \t\t"+SizeOf.sizeOf(1));
System.out.println("Char: \t\t"+sizeOf('a'));
System.out.println("Long: \t\t"+SizeOf.sizeOf(1L));
System.out.println("Double: \t\t"+SizeOf.sizeOf(1.0D));

输出

Integer: 		16
Char: 		16
Long: 		16
Double: 		16

为什么全都是16字节呢?

原因是Java中所有类都是Object的子类,而java.lang.Object空壳对象本身占用8个字节。

System.out.println("Object: \t\t"+ SizeOf.deepSizeOf(new Object())); //8byte

另外,对象在Java HotSpot VM中都是按8字节对齐(无论32bit还是64bit),也就是说不满8字节的,填充至8字节,比如Integer原本实际占用8+4=12字节,但是需要按8字节对齐,因此就是16字节了。而Long和Double本身刚好占满16字节,不需要对齐。

(2)数组

int[] array=new int[2];
System.out.println("array:"+SizeOf.deepSizeOf(array)); //24byte

此处声明了一个包含2个int型元素的数组,计算大小为8+4*2=16字节,为什么会输出24字节呢?

原因是,每个数组都包含一个4字节的空间用来记录数组的长度。所以,实际大小为8+4*2+4=20,然后按8字节对齐为24字节。

(3)字符串

System.out.println("string: \t"+ SizeOf.deepSizeOf(new String("1")));//40byte

String对象大小分2部分计算:

a)内部有四个成员变量占用空间:

三个4个字节的int类型offset、count、hash(3x4=12字节),一个引用类型4字节(char[]数组的引用),String继承了java.lang.Object,“空壳”对象也有8个字节。 合计:12+4+8=24byte

b)char[]占用空间:

8(空壳)+4(数组长度)+2(一个字符"1"占用的空间)=14byte -> 对齐后=16byte

所以这个String的实际长度是24+16=40byte

 

结束语

以上就是通过SizeOf测定对象占用内存方法。

另外,欢迎访问我的另外一篇blog:JVM堆中对象结构 http://shensy.iteye.com/blog/1879789

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics