Java对象到底多大?
2016-10-31 23:08
204 查看
很多时候我们想知道一个Java对象到底有多大, 但Java没有像C语言那样提供一个类似于sizeof的方法。作为Java老司机的你,是否考虑过这个问题?
在《深入理解Java虚拟机》这边书中提到HotSpot虚拟机是8字节对齐的, 一个Java对象包括对象头(Header),实例数据(Instance Data)和对齐填充(Padding), 现在的HotSpot虚拟机一般运行在64位电脑上。
不管是否压缩,即UseCompressOops。 Java对象占用字节数都是8的整数倍,8的整数倍,8的整数倍!!! 重要的事情说3遍。
Object obj = new Object(); 请问在这句代码使用了多大内存? 不考虑压缩(XX:-UseCompressedOops),答案是24个字节, 其中引用obj在Java栈里使用8个字节, new Object在Java堆里使用16个字节。
Java Instrumentation类的getObjectToSize方法可以测量Java对象的大小, 要使用javagent注入的方式得到Instrumentation的引用。
我总结为表格, 方法理解
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
Java语言有8种原生数据类型, 即8种类型关键字。原生类型(primitive type)的内存占用如下:
以上的8种数据类型压缩前后占用空间大小不变, 在32位/64位机器上占用空间一致, 即Java是平台无关的。
下边是我总结的计算方法:
有兴趣的可以下载我用 IntelliJ写的demo工程:http://download.csdn.net/detail/brycegao321/9670233
1、新建Java工程;
![](https://img-blog.csdn.net/20161101172724180?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20161101175055189)
![](https://img-blog.csdn.net/20161101175241473)
2、设置输出为jar包, 得到MANIFEST.MF文件。
![](https://img-blog.csdn.net/20161101175317552)
![](https://img-blog.csdn.net/20161101175357145)
选中 Build on make选项。
![](https://img-blog.csdn.net/20161101175524772)
修改MANIFEST.MF, 注意Boot-Class-Path后面有个空格!!!
![](https://img-blog.csdn.net/20161101180125124)
编译后生成jar包。
测试代码:
输出: 左边是没压缩, 右边是压缩的, 单位是字节。 注意cmd命令啊!
java -javaagent:CalcSize.jar -XX:+UseCompressedOops -jar CalcSize.jar
java -javaagent:CalcSize.jar -XX:-UseCompressedOops -jar CalcSize.jar
![](https://img-blog.csdn.net/20161101180149586)
参考:
http://www.jroller.com/maxim/entry/again_about_determining_size_of http://yueyemaitian.iteye.com/blog/2033046 http://www.importnew.com/14948.html
在《深入理解Java虚拟机》这边书中提到HotSpot虚拟机是8字节对齐的, 一个Java对象包括对象头(Header),实例数据(Instance Data)和对齐填充(Padding), 现在的HotSpot虚拟机一般运行在64位电脑上。
不管是否压缩,即UseCompressOops。 Java对象占用字节数都是8的整数倍,8的整数倍,8的整数倍!!! 重要的事情说3遍。
Object obj = new Object(); 请问在这句代码使用了多大内存? 不考虑压缩(XX:-UseCompressedOops),答案是24个字节, 其中引用obj在Java栈里使用8个字节, new Object在Java堆里使用16个字节。
Java Instrumentation类的getObjectToSize方法可以测量Java对象的大小, 要使用javagent注入的方式得到Instrumentation的引用。
/** * Returns an implementation-specific approximation of the amount of storage consumed by * the specified object. The result may include some or all of the object's overhead, * and thus is useful for comparison within an implementation but not between implementations. * * The estimate may change during a single invocation of the JVM. * * @param objectToSize the object to size * @return an implementation-specific approximation of the amount of storage consumed by the specified object * @throws java.lang.NullPointerException if the supplied Object is <code>null</code>. */ long getObjectSize(Object objectToSize);
我总结为表格, 方法理解
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
Java语言有8种原生数据类型, 即8种类型关键字。原生类型(primitive type)的内存占用如下:
类型 | 内存占用(字节) |
boolean | 1 |
byte | 1 |
short | 2 |
char | 2 |
int | 4 |
float | 4 |
long | 8 |
double | 8 |
下边是我总结的计算方法:
对象大小:(对象头 + 实例数据 + padding)%8等于0, padding是补齐成8的整数倍 下面各个对象的大小都是按照上述顺序计算的。 | |||
对象 | 已压缩(字节) -XX:+UseCompressedOops | 未压缩(字节) -XX:-UseCompressedOops | 说明 |
new Object() | 12+Padding=16 | 16 | 压缩前对象头占16个字节,压缩后占12个字节。 |
static class A { int a; } new A() | 12+4=16 12是对象头,4是int型大小 | 16+4+Padding=24 16是对象头大小,4是int型大小 | 对象头压缩前占16个字节,压缩后占12个字节;int型占4个字节。 |
static class B { int a; int b; } new B() | 12+4+4+Padding=24 12是对象头,第一个4是变量a,第二个4是变量b, paddinb是余8补齐的4. | 16+4+4=24 | 区别是已压缩要添加8字节对齐的Padding。 |
static class B2 { int b2a; Integer b2b; } new B2() | 12+4+4=24 12是对象头,第一个4是变量b2a,第二个4是b2b引用。 | 16+4+8+Padding=32 | 在64位机器上引用压缩前占8个字节,压缩后占4个字节。 |
new Object[3] | 16+3*4+Padding=32 16是对象头,4是单个引用大小。 | 24+8*3=48 24是对象头,8是单个引用大小 | 数组对象的对象头在压缩前占24个字节,压缩后占16个字节。 |
new Object[1] | 16+1*4+padding=24 16是对象头,4是引用大小; | 24+1*8=32 24是对象头,8是单个引用大小 | |
单一对象头 | 12 | 16 | |
数组对象头 | 16 | 24 | |
引用 | 4 | 8 |
1、新建Java工程;
2、设置输出为jar包, 得到MANIFEST.MF文件。
选中 Build on make选项。
修改MANIFEST.MF, 注意Boot-Class-Path后面有个空格!!!
MANIFEST.MF要添加下面三行 Premain-class: SizeUtils (实现premain方法,得到Instrumentation的引用) Can-Redefine-Classes: false Boot-Class-Path: (注意:Path:后面有空格,否则编译不过!!!)
编译后生成jar包。
测试代码:
public class SizeTest { /** * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 = 16 * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + padding/4 = 24 */ static class A { int a; } /** * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24 * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + 4 = 24 */ static class B { int a; int b; } /** * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24 * -XX:-UseCompressedOops: mark/8 + metedata/8 + 8 + 4 + padding/4 = 32 */ static class B2 { int b2a; Integer b2b; } /** * 不考虑对象头: * 4 + 4 + 4 * 3 + 3 * sizeOf(B) */ static class C extends A { int ba; B[] as = new B[3]; C() { for (int i = 0; i < as.length; i++) { as[i] = new B(); } } } static class D extends B { int da; Integer[] di = new Integer[3]; } /** * 会算上A的实例字段 */ static class E extends A { int ea; int eb; } public static void main(String[] args) throws IllegalAccessException { System.out.println("sizeOf(new Object())=" + SizeUtils.sizeOf(new Object())); System.out.println("sizeOf(new A())=" + SizeUtils.sizeOf(new A())); System.out.println("sizeOf(new B())=" + SizeUtils.sizeOf(new B())); System.out.println("sizeOf(new B2())=" + SizeUtils.sizeOf(new B2())); System.out.println("sizeOf(new B[3])=" + SizeUtils.sizeOf(new B[3])); System.out.println("sizeOf(new C())=" + SizeUtils.sizeOf(new C())); System.out.println("fullSizeOf(new C())=" + SizeUtils.fullSizeOf(new C())); System.out.println("sizeOf(new D())=" + SizeUtils.sizeOf(new D())); System.out.println("fullSizeOf(new D())=" + SizeUtils.fullSizeOf(new D())); System.out.println("sizeOf(new int[3])=" + SizeUtils.sizeOf(new int[3])); System.out.println("sizeOf(new Integer(1)=" + SizeUtils.sizeOf(new Integer(1))); System.out.println("sizeOf(new Integer[0])=" + SizeUtils.sizeOf(new Integer[0])); System.out.println("sizeOf(new Integer[1])=" + SizeUtils.sizeOf(new Integer[1])); System.out.println("sizeOf(new Integer[2])=" + SizeUtils.sizeOf(new Integer[2])); System.out.println("sizeOf(new Integer[3])=" + SizeUtils.sizeOf(new Integer[3])); System.out.println("sizeOf(new Integer[4])=" + SizeUtils.sizeOf(new Integer[4])); System.out.println("sizeOf(new A[3])=" + SizeUtils.sizeOf(new A[3])); System.out.println("sizeOf(new E())=" + SizeUtils.sizeOf(new E())); System.out.println("sizeOf(new HashMap)=" + SizeUtils.sizeOf(new HashMap<String,Object>())); } }
输出: 左边是没压缩, 右边是压缩的, 单位是字节。 注意cmd命令啊!
java -javaagent:CalcSize.jar -XX:+UseCompressedOops -jar CalcSize.jar
java -javaagent:CalcSize.jar -XX:-UseCompressedOops -jar CalcSize.jar
参考:
http://www.jroller.com/maxim/entry/again_about_determining_size_of http://yueyemaitian.iteye.com/blog/2033046 http://www.importnew.com/14948.html
相关文章推荐
- 一个Java对象到底占用多大内存?
- 一个Java对象到底有多大
- 一个Java对象到底占多大内存?
- 一个Java对象到底占多大内存?(转)
- 一个Java对象到底占用多大内存
- 一个Java对象到底占用多大内存?
- 一个Java对象到底占用多大内存?
- 一个Java对象到底占用多大内存?
- 一个Java对象到底占多大内存
- 一个Java对象到底占多大内存?
- 一个Java对象到底占用多大内存?
- 一个Java对象到底占用多大内存?
- 一个Java对象到底占用多大内存
- 一个Java对象到底占用多大内存
- 一个Java对象到底占用多大内存?
- 一个Java对象到底占多大内存?
- java对象到底占用多大内存?
- 一个Java对象到底占多大内存?
- 一个Java对象到底占多大内存?
- 一个java对象到底占多大内存?