http://shensy.iteye.com/blog/1765760原文地址
一、前言
最近在学习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