所谓内存布局,指的是一个对象在内存中的组成。通常由三部分组成
- 对象头(包含MarkWord、Klass Pointer、数组长度)
- 对象实例数据
- 对齐(一个完整对象需要为8个字节的倍数),可能没有
所以在开启指针压缩的条件下,一个空Object对象为16个字节:
8字节 MarkWord
4字节 元数据指针
4字节 对齐
一个Long对象为24个字节,Long对象的成员变量只有一个long,而long是占有8个字节的:
8字节 MarkWord
4字节 元数据指针
8字节 long
4字节 对齐
对象头
MarkWord
MarkWord中包含了很多信息,比如锁信息、hashcode、gc信息、线程信息,在对象不同的阶段存储不同的信息。 markword-64.png- Hashcode
在无锁状态下存储,开始时没有的,调用过对象的一次hashcode()方法之后,会将hashcode存储到对象头。 - 分代年龄
在GC中,对象由年轻代晋升老年的的判断标准之一就是这个分代年龄,因为这里只使用了4位进行存储,所以津国这个分代年龄可以调整,但是最大值也只能是15。 - 偏向锁信息
现在对象创建默认是偏向锁状态,可以通过参数配置。 - 锁标志位
受synconized关键字影响,由synconized修饰的对象,会被当成一把锁,在锁竞争过程中会通过锁标志位来标记当前的锁状态。
关于synconized关键字,参看另一篇文章:https://www.jianshu.com/p/be8ccd456b32
元数据指针
我们知道JVM加载一个类之后,解析出这个类的信息放入方法区,并会生成一个class对象放在了堆中。元数据指针指向的是方法区内部的类信息。
类加载机制概念
Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制。
Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能,这里就是我们经常能见到的Class类。
- 装载:查找和导入Class文件;
- 链接:把类的二进制数据合并到JRE中;
(a)校验:检查载入Class文件数据的正确性;
(b)准备:给类的静态变量分配存储空间;
(c)解析:将符号引用转成直接引用;- 初始化:对类的静态变量,静态代码块执行初始化操作
- 使用
- 卸载
注意第一步的装载:
类的装载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
方法区
方法区是JVM规范中,规划的一块区域。hospot对其实现在1.8之前是永久代,1.8之后是元空间,1.7是过渡阶段。
使用元空间的优点
- 不会出现“java.lang.OutOfMemoryError: PremGen space”异常
- 字符串常量池迁移到堆中,避免溢出
- 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
- 通过类加载器来控制垃圾回收。
元空间Metaspace
分为两个部分Klass Metaspace 和NoKlass Metaspace。
- Klass Metaspace
- Klass Metaspace就是用来存klass的,就是class文件在jvm里的运行时数据结构(不过我们看到的类似A.class其实是存在heap里的,是java.lang.Class的对象实例)。
- 这部分默认放在Compressed Class Pointer Space中,是一块连续的内存区域,紧接着Heap,和之前的perm一样。通过-XX:CompressedClassSpaceSize来控制这块内存的大小,默认是1G。
- Compressed Class Pointer Space不是必须有的,如果设置了-XX:-UseCompressedClassPointers,或者-Xmx设置大于32G,就不会有这块内存,这种情况下klass都会存在NoKlass Metaspace里。
- NoKlass Metaspace
- NoKlass Metaspace专门来存klass相关的其他的内容,比如method,constantPool等,可以由多块不连续的内存组成。
- 这块内存是必须的,虽然叫做NoKlass Metaspace,但是也其实可以存klass的内容,上面已经提到了对应场景。
- NoKlass Metaspace在本地内存中分配。
这里我们说的类型指针指向的是Klass Metaspace地址。
指针压缩
- 64位平台上默认打开
- 设置-XX:+UseCompressedOops压缩对象指针, oops指的是普通对象指针(ordinary object pointers), 会被压缩成32位。
- 设置-XX:+UseCompressedClassPointers压缩类指针,会被压缩成32位,这里指类对象。
如果设置了-XX:-UseCompressedClassPointers,或者-Xmx设置大于32G,则这个参数不生效。
参考这篇文章:https://blog.csdn.net/liuxiao723846/article/details/91981757
网友评论