【超详细】Java各种类型所占用的内存空间究竟多大? |
您所在的位置:网站首页 › array所占的空间 › 【超详细】Java各种类型所占用的内存空间究竟多大? |
文章目录
准备工作对象内存占用情况使用Jprofiler进行验证【关于Retained Size的意思】
基本类型的包装类型内存占用数组占用内存空间String 对象内存占用空间总结
准备工作
不喜欢被蒙在鼓里的感觉,鉴于网上大神们说法不一致,我决定亲自实验,探究究竟Java各个类型占用空间情况。 实验环境为 jdk1.8 hotspot虚拟机+win10系统使用Jprofiler进行探究(IDEA插件直接下载)![]() 已知:Java对象的内存布局包括:1.对象头;2.实例数据;3.补充数据; 在jdk6之后的版本中,指针压缩是被默认开启的,开启指针压缩,对象头占用12bytes(其中markword 8字节,Klasspointer 4字节),不开启指针压缩则对象头占用16bytes(其中markword 8字节,Klasspointer 8字节)。【如果为数组还会存储数组长度,上面链接指向的文章中都有记录】 至于实例数据,原生类型(primitive type)的内存占用如下: 下面图片是我在别处截的,这个图存在一些问题。。这也是为什么自己想亲自写博客输出的原因之一,不喜欢被蒙在鼓里不清不楚的感觉。。 boolean在作为数组的时候会被编译器翻译成bytes[ ],所以只占一个字节,但是在单独作为实例变量的时候,boolean会被编译器翻译成int,占4个字节,所以具体多大还得具体分析! 至于实例数据中的,对象引用:开启指针压缩的内存优化,对象引用占用4字节,不开启的话占用8字节。 补充数据,是将当前的对象大小向上按照8字节的倍数进行补充,其原因上文连接中也介绍了。 使用Jprofiler进行验证【注意使用Jprofile查看内存,不能让主线程立马结束,不然查看不了内存占用状况,需要写个sleep】 写个例子测试一下,下面是一个Wang的类,其中是一些实例变量 class Wang { private String name; private int age; private int[] arr = {1, 2, 3}; private boolean status; }我们写个main方法进行测试一下这个对象占用了多少个字节 public static void main(String[] args) throws InterruptedException { Wang wang = new Wang("wangz7",18,true); Thread.sleep(600 * 1000); System.out.println(wang); }如图:我们发现这个对象占用了32个字节 (推测:对象头12字节 + String4字节 + int4字节 + arr数组引用4字节 + boolean4字节 + 6字节的补充数据) 指的是:该对象指向别的对象,导致别的对象称为可达对象,那么Retained大小就包括自身的对象大小 + 指向的对象大小。 在这里wang对象持有了两个引用(String和int[ ]),说明这个String对象加上数组共占用64-32=32字节大小 引用关系如图所示 可以这么理解。只要是关闭指针压缩,那么一个包装对象在堆中就占用24字节空间 如果开启了指针压缩,那么除了双精度double以及Long这两个基本类型占8字节的包装类型,堆中占用还是24字节,其他的基本类型对应的包装类型均占16字节。 数组占用内存空间探究这个问题我们可以用到这个工具:openjdk.jol 先添加依赖: org.openjdk.jol jol-core 0.14然后可以参考我这个例子【这里写了个对象数组,并打印其对象内存占用情况】 class Wang { private String name; private int age; private int[] arr = {1, 2, 3}; private boolean status; public Wang(String name, int age, boolean status) { this.name = name; this.age = age; this.status = status; } } public class Solution { public static void main(String[] args) throws InterruptedException { System.out.println(VM.current().details()); Wang[] wang = new Wang[10]; System.out.println(ClassLayout.parseInstance(new Wang[10]).toPrintable()); } }输出: ![]()
可以看到除了一个char数组和一个int值,其他的是static修饰的不占用对象的内存。 因此一个String对象在开启指针压缩的64位机上,内存大小是(12字节对象头 + char数组引用4字节 + int4字节 + 4字节填充数据 = 24字节) 之后再来计算char[ ]数组大小;毕竟String对象有数组的成分,在JDK1.7到JDK1.9之前是char[ ]。因此大小为(16字节对象头 + 字符串长度 * char占用2字节 + 补充数据),因此上面字符串“wang”的char[]数组部分占用16+4*2 = 24字节的大小 因此!在64位机下默认开启指针压缩,String str = new String(“wang”);这个str字符串对象的大小应该是String部分的24字节 + char数组部分的24字节 = 48字节 总结 稍稍了解这里就够了本篇文章主要记录了一下各种类型占用的内存大小,以及使用jol和jprofiler证明对象的大小。关于指针压缩、Retained Size、jprofiler的使用,我会记录下在并把连接放到下面:————— END ————— |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |