多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### 对象的指向 先来看一段代码: ~~~ package com.zwx.jvm; public class HeapMemory {     private Object obj1 = new Object();     public static void main(String[] args) {         Object obj2 = new Object();     } } ~~~ 上面的代码中,obj1 和obj2在内存中有什么区别? 我们先来回忆一下JVM系列1的文章中有提到,方法区存储每个类的结构,比如:运行时常量池、属性和方法数据,以及方法和构造函数等数据。所以我们这个obj1是存在方法区的,而new会创建一个对象实例,对象实例是存储在堆内的,于是就有了下面这幅图(**方法区指向堆**): ![](https://img.kancloud.cn/c4/f8/c4f8a7f98f59e4bf621f6d8ee603fae3_560x278.png) 而obj2 是属于方法内的局部变量,存储在Java虚拟机栈内的栈帧中的局部变量表内,这就是经典的**栈指向堆**: ![](https://img.kancloud.cn/9c/aa/9caadb1b451053cecc4125ba0c0c750b_789x431.png) 这里我们再来思考一下,我们一个变量指向了堆,而堆内只是存储了一个实例对象,那么堆内的示例对象是如何知道自己属于哪个Class,也就是说这个实例是如何知道自己所对应的类元信息的呢?这就涉及到了一个Java对象在内存中是如何布局的 ### Java内存模型 对象内存中可以分为三块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding),**以64位操作系统为例(未开启指针压缩的情况)**Java对象布局如下图所示: ![](https://img.kancloud.cn/39/49/394970c1e42926bcc2d139ad75c1150f_833x282.png) 其中对象头中的Mark Word中的详细信息在文章synchronized锁升级原理中有详细介绍。上图中的对齐填充不是一定有的,如果对象头和实例数据加起来刚好是8字节的倍数,那么就不需要对齐填充 ### [Object obj=new Object()占用字节] 这是网上很多人都会提到的一个问题,那么结合上面的Java内存布局,我们来分析下,以64位操作系统为例,new Object()占用大小分为两种情况: * 未开启指针压缩     占用大小为:**8(Mark Word)+8(Class Pointer)=16字节** * 开启了指针压缩(默认是开启的)     开启指针压缩后,Class Pointer会被压缩为4字节,最终大小为:**8(Mark Word)+4(Class Pointer)+4(对齐填充)=16字节** 结果到底是不是这个呢?我们来验证一下。首先引入一个pom依赖: ~~~ <dependency>     <groupId>org.openjdk.jol</groupId>     <artifactId>jol-core</artifactId>     <version>0.10</version> </dependency> ~~~ ``` package com.zwx.jvm; import org.openjdk.jol.info.ClassLayout; publicclass HeapMemory { public static void main(String\[\] args) {         Object obj = new Object();         System.out.println(ClassLayout.parseInstance(obj).toPrintable());     } } ``` 输出结果如下: ![](https://img.kancloud.cn/5b/3b/5b3b82c44bf65757a7e93b3b5e18f560_1058x265.png) 最后的结果是16字节,没有问题,这是因为默认开启了指针压缩,那我们现在把指针压缩关闭之后再去试试 ![](https://img.kancloud.cn/85/e2/85e21102e228867d2624262ce1df9424_770x180.png) 再次运行,得到如下结果: ![](https://img.kancloud.cn/de/a4/dea48971cdbcc84e2c0063894bc37a71_1014x269.png) 可以看到,这时候已经没有了对齐填充部分了,但是占用大小还是16位。 下面我们再来演示一下如果一个对象中带有属性之后的大小。 新建一个类,内部只有一个byte属性: ![](https://img.kancloud.cn/08/3d/083dc37d17a02aad365d107d6fd8282a_1322x1030.png) 开启指针压缩,占用16字节: ![](https://img.kancloud.cn/3c/cd/3ccd850e2d74f8bf397ab8971ec78f66_1062x266.png) 关闭指针压缩,占用24字节: ![](https://img.kancloud.cn/27/c0/27c0b6422c077f4890af15bea660b371_1080x292.png) 这个时候就能看出来开启了指针压缩的优势了,如果不断创建大量对象,指针压缩对性能还是有一定优化的