JVM(三)堆与对象

2022-03-30  本文已影响0人  NIIIICO

一、堆的结构

堆内存结构

JVM中,堆被划分成两块区域:年轻代(young):老年代(old)= 1:2;年轻代又可以划分为Eden(伊甸园):From Survivor(幸存者):To Survivor (幸存者)= 8:1:1;以上比例都是默认比例,可以通过参数进行修改。

为什么要分代?根本原因是为了优化GC性能。在java程序运行过程中,大部分对象都是临时对象。
不分代,GC时需要对heap的所有区域扫描,比较消耗性能;
分代,GC时常规情况下只处理年轻代,就可以回收大量空间,满足程序运行需要;特殊情况下再处理老年代。从而优化GC运行效率。

二、对象的分配

对象分配过程
1、根据逃逸分析,判断是否可以在栈中分配

逃逸:一个对象如果被外部其他类调用,或做用于属性中,此种现象为对象逃逸。

非逃逸:一个对象的作用域仅限于方法内部,此种现象为非逃逸。
逃逸分析:Hotspot虚拟机可以分析对象的使用范围,从而决定是否在Heap中分配。如某个对象没有逃逸,在虚拟机上可以做如下优化:

(1)锁消除:我们知道同步锁比较消耗性能,由于当前对象只在一个线程中访问,可以取消同步操作。

(2)标量替换

(3)栈上分配:如果对象未发生逃逸,该对象就可以分配在栈内存中,和方法的生命周期一致,随着栈帧出栈时销毁,从而减少GC运行频率。

2、大对象直接分配到Old

Young一般都不大,如果存储大对象,Young很容易满,导致频繁触发GC。GC后很可能还是会超过Yong的存储,将对象转存到Old区,产生大内存复制。因此直接将大对象分配到Old区,减少上述操作。

3、TLAB判断

TLAB:Thread Local Allocation Buffer,线程本地分配缓存,TLAB在Eden区分配,默认只有Eden的1%,所以大对象无法在TLAB分配。

4、Young、Old、GC

三、对象数据

1、对象结构
对象结构

在Hotspot虚拟机中,对象在内存中的结构可分为三部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

(1)对象头:

(2)实例数据:对象真正存储的数据,包含自有的字段和父类继承的。
(3)数据填充:没有实际意义,起着占位符的作用,当实例数据没有对齐时,就需要通过对齐填充来补全。

2、对象的创建方式
3、对象的创建过程

(1)查找类元信息
根据new的参数,在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析、初始;如果没有,先执行相应的类加载过程。

(2)内存分配及并发
查找到类元信息后,虚拟机将为新生对象分配内存,对象所需的内存在类被解析加载进入元空间之后就可以计算出来:

(3)初始化数据
内存分配完成后,虚拟机需要将分配到的内存空间初始化为零值(不包括对象头),保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

(4)设置对象头
初始化零值之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。

(5)执行init
执行<init>方法,为属性赋值、执行构造方法。

上一篇下一篇

猜你喜欢

热点阅读