JVM垃圾回收

可查看思维导图思虑更清晰:https://www.processon.com/view/link/5e268e3ae4b0d27af17eddc0

JVM内存分配与回收
对象优先在Eden区分配
大多数情况下,对象在Eden区分配。当Eden区没有足够空间分配时,虚拟机将触发一次Minor GC。
新生代GC(Minor GC):指发生在新生代的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。
老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC的慢10倍以上。

判断对象是否可以被回收有如下算法:
引用计数法:给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就是不可能再被使用的。这个方法既简单而且效率高,但是这种算法很难对象之间相互循环引用的问题。所以目前主流的虚拟机中并没有选择这个算法来管理内存。
可达性分析算法:这个算法就是通过一系列的"GC Roots"的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链接时,说明该对象是可回收的。GC Roots根节点:类加载器,Thread,虚拟机栈的本地变量表,static成员,常量引用,本地方法栈的变量等等。

finalize()方法:判断对象最终是否存活
在可达性分析算法中不可达的对象,也并非是"非死不可"的,这时候他们暂时处于"缓刑"阶段,如果要让一个对象正在死亡,需要经历再次标记过程。

  1. 第一次标记并进行一次筛选。
    筛选的条件是判断该对象是否有必要执行finalize()方法。
    当对象没有覆盖finalize方法,或者finalize方法已经被虚拟机调用过,这种情况下虚拟机会视为"没有必要执行",这时候对象回收。
  2. 第二次标记
    如果该对象被判定为有必要执行finalize()方法,那么该对象会被放置在一个名为:F-Queue的队列之中,并在稍后由一条虚拟机自动建立的,低优先级的Finalizer线程去执行,但并不会等待它运行结束。这样做的原因是,如果一个对象finalize()方法中执行缓慢,或者死循环,将很可能导致F-Queue队列中的其他对象永久处于等待状态,很有肯能会导致整个内存回收系统崩溃。
    finalize()方法是对象逃离死亡的最后机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象要在finalize()中成功拯救自己,就需要重新与引用链上的任何一个对象建立关联即可,例如:把自己赋值给某个类变量或对象的成员变量,那么第二次标记时它将被移除"即将回收"的集合。如果对象这时还没有逃脱,就会被真的回收了。

垃圾收集算法
标记-清除算法:首先标记出需要回收的算法,在标记完成后统一回收所有标记的对象。它是最基础的收集算法,但是会出现两个明显的问题:效率问题,空间问题(标记清除后会产生大量连续的碎片)
复制算法:为了解决效率问题及空间问题,“复制"收集算法就出现了。它可以将内存分为大小相同的两块,每一次使用其中的一块。当这一块内存使用完了后,就会将还存活的对象复制到另一块,然后把之前的空间一次清理掉。
标记-整理算法:根据老年代的特点特出的一种标记算法,标记过程仍然与"标记-清除"算法一样,只不过步骤不是直接回收可回收对象,而是让所有存活的对象向一段移动,然后直接清理掉段边界以外的内存。
分代收集算法:当前虚拟机的垃圾收集算法都采用分代收集算法,这种算法只是一种思想,只是根据对象存活的周期的不同将分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾算法。比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择"标记-整理”,"标记-清除"算法来进行垃圾收集。

垃圾收集器
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。
虽然我们对各个收集器做了比较,但并非为了挑选出一个最好的收集器。因为到现在为止还没有一个最好的垃圾收集器出现,更加没有万能的垃圾收集器,我们能做的就是在不同的场景选择出合适的垃圾收集器。如果有一种完美的收集器HotSpot虚拟机也就没必要实现那么多不同的垃圾搜集器了

Serial收集器
单线程收集器,收集时只会有一条垃圾收集线程去完成工作,并且它在进行垃圾收集的时候必须暂停其他所有的工作线程,直到垃圾收集结束。
Serial收集器优点在于它简单而高效(与其他收集器的单线程相比),没有线程交互的开销,自然可以获得很高的单线程收集率。

ParNew收集器
该收集器是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其他行为和Serial收集器完全一样。
这是运行在Server模式下的虚拟机的首要选择,除了Serial收集器外,只有它能与CMS收集器(真正意义上的并发收集器)配合工作。

Parallel Scavenge收集器
该收集器类似于ParNew收集器,是Server模式(内存大于2g,2个cpu)下的默认收集器。
它的特点在于:Parallel Scavenge收集器关注点是吞吐量(高效率的利用CPU)。CMS等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验)。所谓吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值。

CMS收集器
主要是old区使用,CMS收集器是一种以获取最短回收停顿时间为目标的收集器。它非常适合注重在用户体验上,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程于用户线程(基本上)同时工作。
CMS收集器是一种"标记-清除"算法实现的,它的运作过程相比于前面几种垃圾收集器来说更复杂一些。
整个过程分为4步骤:
1.初始标记:暂停所有的其他线程(STW),并记录下直接于root相连的对象,数度很快。
2.并发标记:同时开启GC和用户线程,用一个闭包结构去记录可达对象。在该阶段无法保证包含了所有可达对象。因为用户线程也在不断跟新引用域,所以GC线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。
3.重新标记:重新标记阶段就是为了修正并发标记期间用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的时间会稍长,但远远比并发标记短。
4.并发清除:开启用户线程,同时GC线程开始对为标记的区域做清扫。
主要优点:并发收集、低停顿。但是它有下面三个明显的缺点:
对CPU资源敏感(会和服务抢资源);
无法处理浮动垃圾(在java业务程序线程与垃圾收集线程并发执行过程中又产生的垃圾,这种浮动垃圾只能等到下一次gc再清理了);
它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生。

G1收集器
G1是一款面向服务器的垃圾收集器,主要针对配置多个处理器及大容量内存的机器,以及高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征。
G1将Java堆划分为多个大小相等的独立区域(Region),虽保留新生代和老年代的概念,但不再是物理隔阂了,它们都是(可以不连续)Region的集合。分配大对象(直接进Humongous区,专门存放短期巨型对象,不用直接进老年代,避免Full GC的大量开销)不会因为无法找到连续空间而提前触发下一次GC。
被视为JDK1.7中HotSpot虚拟机的一个重要进化特征。它具备以下特点:
并行与并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短Stop-The-World停顿时间。部分其他收集器原本需要停顿Java线程来执行GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。
分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。
空间整合:与CMS的“标记–清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。
可预测的停顿:这是G1相对于CMS的另一个大优势,降低停顿时间是G1 和 CMS 共同的关注点,但G1 除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内完成垃圾收集。
G1收集器的运作大致分为以下几个步骤:
初始标记(initial mark,STW):在此阶段,G1 GC 对根进行标记。该阶段与常规的 (STW) 年轻代垃圾回收密切相关。
并发标记(Concurrent Marking):G1 GC 在整个堆中查找可访问的(存活的)对象。
最终标记(Remark,STW):该阶段是 STW 回收,帮助完成标记周期。
筛选回收(Cleanup,STW):筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。

G1收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的Region(这也就是它的名字Garbage-First的由来)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了GF收集器在有限时间内可以尽可能高的收集效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值