JVM 总结(二)


heap区是GC最频繁的,也是理解GC机制最重要的区域,了解JVM GC原理堆系统调优非常有用,若系统频繁发生FGC,整个系统的响应会非常卡顿,甚至崩溃。堆区由所有线程共享,在虚拟机启动时创建。堆区主要用于存放对象实例及数组,所有new出来的对象都存储在该区域。

1. java与c++回收机制

java是通过垃圾回收器处理垃圾,开发效率高,执行效率低。
c++的垃圾是需要手动处理的,开发效率低,执行效率高;但是,手动处理会出现忘记回收或者多次回收的问题,忘记回收会造成内存泄漏,回收多次会引起某些对象被非法引用。

2. 定位垃圾

2.1 什么是垃圾?

程序中没有任何引用的对象,是GC回收的对象。

2.2 垃圾查找算法

2.2.1 引用计数法(Reference Count)

heap中每一个对象都有一个引用计数,对象被创建并分配给某一变量时,引用计数为1;每被引用一次,计数加1,当某个对象的引用超过生命周期或者被设为新值时,引用次数减1。引用计数变为0时,就可以被当作垃圾被回收,若被回收的对象还引用其他对象时,这些对象的引用计数减1。
引用计数法,执行快,交织在程序运行中,适合于程序不被长时间打断的实时环境。但是,引用计数法不能定位到循环引用/递归引用的对象。

2.2.2 根可达算法(Root Searching)

以GC Roots为起点,向下搜索,所有走过的路径称为引用链,若某一对象没有引用链连接时,说明GC Root到此对象不可达,此对象就可以被当作垃圾被回收。
目前Hotspot采用的就是根可达算法。
被定义为GC Root的对象包括:

  • JVM Stack(虚拟机栈中引用的对象)
  • Native Method Stack(本地方法栈中引用的对象)
  • Runtime constant pool(运行时常量池引用的对象)
  • static references in method area (方法区中静态属性引用的对象)

3. 常见的垃圾回收算法

3.1 标记清除算法(Mark-Sweep)

从GC Root开始扫描,标记存活的对象,全部标记完之后,扫描整个区间,回收未被标记的对象。
优点,算法简单。
缺点,需要进行两次扫描,一次标记,一次清除,效率偏低,而且容易产生碎片。
适用场景,适用于存活对象较多的场景。

3.2 拷贝算法(Copying)

将堆栈一分为二,jvm生成的新对象放在一半空间中,GC回收时,把可达的对象copy到另一半空间,这一半空间剩下的直接回收。
优点,扫描一次,效率提高,不会产生碎片。
缺点,需要进行对象的移动复制,调整对象的引用,内存被一分为二,会造成空间的浪费。
适用场景,适用于存活对象较少的情况,适合伊甸区。

3.3 标记整理/压缩算法(Mark-Compact)

清除方式和Mark-Sweep一样,先标记存活的对象,然后清除未标记的,不同的时,在回收未标记的对象时,先把标记存活的对象移动整理到空闲空间,然后再进行回收。
优点,不会产生碎片。
缺点,需要扫描两次,还需要进行对象的移动,效率偏低。

4. JVM内存分代模型

目前,垃圾回收器有的使用分代模型,也有部分垃圾回收器使用不分代模型。

4.1 JVM 分代

一般新生代与老年代的默认占比是1:8。用参数 -XX:NewRatio=8指定比例

4.1.1 新生代(Young generation)

大部分最新创建的对象会被分配在新生代,对新生代的回收,称为 MGC(minor GC)。
新生代被分为一个Eden区和两个Survicor区。

4.1.2 老年代(Tenured/Old generation)

对象在新生代中没有变为不可达,存活下来,就会被copy到老年代,老年代占用的空间比新生代大很多,一般发生GC要少很多,系统中要尽可能减少触发老年代的GC。对象从老年代消失的过程,成为FGC(full/major GC)。

4.1.3 永久代(Method Area)

Method Area是逻辑概念,jdk1.8之前,被称为Permanent generation,jdk1.8之后,被称为Meta generation。

4.2 对象分配过程

在这里插入图片描述

5. 常见的垃圾回收器

5.1 Serial

young generation 的垃圾回收器,是单线程的,串行的垃圾回收器,逻辑上物理上都分代,只会使用一个CPU或一条收集线程进行收集垃圾,而且,在收集垃圾的同时,其他工作线程都必须暂停,直到垃圾收集结束。
暂停的时间称为卡顿时间,STW(Stop The World)。
执行垃圾收集时,需要等待程序到达安全点(Safe Point)才能暂停,安全点的选定标准为,是否具有让程序长时间执行的特征。如产生方法调用/循环跳转等功能的指令时就会产生安全点。
使用场景,内存很小的情况下使用。

5.2 ParNew(Parallel new)

young generation 的垃圾回收器,逻辑上物理上都分代,是Serial回收器的多线程版本,是为了配合CMS的并行回收。

5.3 PS(Parallel Scavenage)

young generation 的垃圾回收器,逻辑上物理上都分代,使用的回收算法是copying,是并行的多线程收集器。
与ParNew的区别是,具有自适应的调节策略,通过参数-XX:+UseAdaptivePolicy,打开这个参数,eden,survivor,old区的比例,晋升old区的年龄等细节都不需要手动设定,JVM会根据性能监测信息,动态调整这些信息。
使用场景,适用于吞吐量优先的场景,如科学计数法。

5.4 Serial Old

old generation 的垃圾回收器,逻辑上物理上都分代,是Serial收集器的老年代版本,也是单线程的的回收器,使用Mark-Compact算法。

5.5 PO(Parallel Old)

old generation 的垃圾回收器,逻辑上物理上都分代,是PS的老年代版本,JDK1.7/1.8 默认的回收器是PS+PO。

5.6 CMS(Concurrent Mark Sweep)

old generation 的垃圾回收器,逻辑上物理上都分代,是JDK1.4引入的。
收集过程

  • initial mark(初始标记),先标记GC Root,以及GC Root能直接关联到的对象,有STW,时间很短,速度很快。
  • concurrent mark(并发标记),最耗时间,GC Root Tracing的过程,不产生STW。
  • remark(重新标记),标记上一阶段因程序继续运作而导致标记变动的部分,会产生STW,比初始阶段时间稍长。
  • concurrent sweep(并发清理),清理未标记的对象,这个阶段会产生新的垃圾,称为浮动垃圾,等待下一次GC清理。
    优点
    降低了STW的时间,CMS开启了并发回收的里程碑。
    缺点
  • 会产生浮动垃圾,在并发清理时,工作线程不会停止,导致清理过程中会有新的垃圾不断产生,档次GC不会回收,需等待下次GC,因此,在清理过程中,需要预留足够的内存空间给用户线程使用,不能等到完全被填满才进行收集,若预留空间无法满足程序需要 ,会出现Concurrent Mode Failure失败,这是JVM会启动Serial Old进行垃圾回收,STW时间会很长。解决方案是通过降低CMS阈值。
  • 会产生碎片化问题,CMS采用的Mark-Sweep算法,所以会出现碎片化问题,若没有足够大的连续空间来分配当前对象,就会触发Full GC。解决方案,使用参数-XX:+UseCompactAtFullCollection
    使用场景,适用于响应优先的场景,如电商网站。

5.7 G1

逻辑上分代,物理上不分代。JDK1.9默认回收器,将堆划分为若干个Region(区域),这些Region分为E(Eden),S(Survivor),O(old),H(Humongous),H区用于存放巨型对象(一个对象占用的空间超过分区容量的50%以上),巨型对象会被直接分配在老年代,若一个H区装不下,G1会寻找连续的H分区来存储,为了找到连续的H区,有时候需要启动FGC。
特点

  • 并发与并发收集,充分利用多核,多CPU的硬件优势,使用多个CPU缩短STW,同时在收集时,可以让java程序并发执行。
  • 压缩空闲空间不会延长GC的暂停时间,采用Mark-Compact算法实现收集,两个Regiob之间采用的是Copying算法实现的,不会产生内存空间碎片。有利于程序长时间运行,分配大对象时也不会由于没有连续空间而提前触发下一次GC。
  • 更易预测GC的暂停时间,可以建立STW预测模型,让使用者明确指定在一个长度为M毫秒的时间片段内,垃圾收集会尽可能地靠近这个时间。

G1收集过程
G1保留了YGC,同时针对老年代的收集采用了MIXGC,尽可能地避免FGC。
1). YGC,Eden区满了之后就会触发YGC,与其他回收期的YGC相同,把存活对象copy到survivor区或晋升到old gen。
在YGC的过程中,old gen的对象不回收,若GC Root可达的对象在old gen中,需要扫描整个老年代,会影响GC整体性能。所以,在CMS中,加入了Card Table的是由bitmap实现的,记录了old gen到y区的引用,若old区有对象引用y区,将它设为dirty,再次扫描时,只扫描dirty card,比扫描整个old gen,代价小很多。在G1中,采用的是Rset(Remembered Set)的数据结构,记录的是其他Regin中对象对本对象的引用,扫描时不需要扫描整个对战,只需要扫描Rset即可,从而减少了GC的工作量。
2). MixGC,G1中应尽量避免FGC,通过扩内存、提高CPU性能,或者降低Mixed GC触发的阈值,让Mixed GC 提早发生(默认为45%)。MixGC回收过程类似CMS回收的4个步骤,最后阶段是筛选回收的阶段,对各个Regin的回收价值和成本进行排序,根据用户期望的GC停顿时间来制定回收计划,这个阶段需要STW,提高收集效率。

使用场景 适用响应时间优先,不需要实现很高的吞吐量的场景,吞吐量比ParNew+CMS 少15%左右。

5.8 ZGC

不分代。采用的标记算法是ColoredPointers(颜色指针)。
关于ZGC后续再详细描述,目前了解不够。

6. 并发标记算法

6.1 三色标记算法

CMS 和 G1 采用的是三色标记算法。
对象分为3中类型,用3中颜色标记:

  • black ,根对象,或自己以及子对象都被扫描。
  • gray,对象本身被扫描,子对象还未被扫描。
  • white,未被扫描的对象,即不可达对象,需要被回收的垃圾对象。
    在并发标记的过程中会出现漏标的现象,即black指向white,gray没有指向white,解决漏标的方案:
  • CMS采用增量更新(incremental update)的方式,在插入的时候记录对象,若有white对象的引用被赋值到black对象,将black重新标记为gray。
  • G1采用SATB(snapshor at the begining)的方式,关注删除的对象,删除时记录对象,push到G1的堆栈,与Rset配合使用,提高效率。

7. 常见的垃圾回收器组合

组合设置参数描述
Serial + Serial Old-XX:+UseSerialGC小型项目会用
ParNew+ Serial Old-XX:+UseParNewGC很少用,某些版本已被弃用
ParNew + CMS + Serial Old-XX:+UseConMarkSweepGC响应优先
PS + PO-XX:+UseParallelGC1.8默认,吞吐量优先
PS + PO-XX:+UseParallelOldGC
G1-XX:+UseG1GC1.9默认,响应优先,吞吐量要求不那么高

8. 垃圾回收器和内存大小的关系

内存大小适用GC
< 100MSerial
100M - 10GParallel
< 20GCMS
< 100GG1
1T - 4TZGC
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值