【详解—JVM中的垃圾回收】—Java入门必看

JVM中的垃圾回收

1.判别死亡对象

a)引用计数器算法(不是HotSpot默认使用的算法)

给每个对象创建一个计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已"死",等待垃圾回收器的回收

引用计数器算法的缺点:循环引用的问题

代码:

/**
* JVM参数 :-XX:+PrintGC
* @author 38134
*
*/
public class Test {
 public Object instance = null;
 private static int _1MB = 1024 * 1024;
 private byte[] bigSize = new byte[2 * _1MB];
 public static void testGC() {
 Test test1 = new Test();
 Test test2 = new Test();
 test1.instance = test2;
 test2.instance = test1;
 test1 = null;
 test2 = null;
 // 强制jvm进行垃圾回收
 System.gc();
 }
 public static void main(String[] args) {
 testGC();
 }
}
[GC (System.gc())  6092K->856K(125952K), 0.0007504 secs] 1

从结果可以看出,GC日志包含" 6092K->856K(125952K)",意味着虚拟机并没有因为这两个对象互相引
用就不回收他们。即JVM并不使用引用计数法来判断对象是否存活。

b)可达性算法(HotSpot默认使用的算法)

通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索
走过的路径称之为"引用链",当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的。以下图为例:
在这里插入图片描述
对象Object5-Object7之间虽然彼此还有关联,但是它们到GC Roots是不可达的,因此他们会被判定为可回收对象。

2.垃圾回收算法

1.标记-清除算法

最基础的收集算法。算法分为"标记"和"清除"两个阶段 : 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象(标记过程见3.1.2章节)。后续的收集算法都是基于这种思路并对其不足加以改进而已。
缺点:

  1. 标记和清除这两个过程的效率都不高
  2. 标记清除后会产生大量不连续的内存碎片:空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。
2.复制算法(新生代回收算法)

"复制"算法是为了解决"标记-清理"的效率问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。
在这里插入图片描述
缺点:内存率低

3.标记-整理算法(老年代回收算法)

针对老年代的特点,提出了一种称之为"标记-整理算法"。标记过程仍与"标记-清除"过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉端边界以外的内存。流程图如下:
在这里插入图片描述
优点:不会产生内存碎片

3.垃圾回收器

收集算法是内存回收的方法论,那么垃圾回收器就是内存回收的具体实现。

1.Serial单线程串行的垃圾回收器(新生代-复制算法)

这个收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束(Stop The World).
应用场景:Serial收集器是虚拟机运行在Client模式下的默认新生代收集器。

2.Serial Old收串行垃圾回收器(老生代)

Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法。
应用场景

  • Client模式
    Serial Old收集器的主要意义也是在于给Client模式下的虚拟机使用。
    *Server模式
    如果在Server模式下,那么它主要还有两大用途:一种用途是在JDK 1.5以及之前的版本中与Parallel Scavenge收集器搭配使用,另一种用途就是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。
3.ParNew收集器(新生代收集器,并行GC,他是Serial的多线程版本【复制算法】)

ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一样,在实现上,这两种收集器也共用了相当多的代码。

应用场景:ParNew收集器是许多运行在Server模式下的虚拟机中首选的新生代收集器。

4. Parallel Scavenge并发垃圾回收器(新生代)

Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器。
应用场景:停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

5.Parallel Old并发垃圾回收器(老年代)

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
应用场景:在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器。
在这里插入图片描述

6.CMS(老年代收集器,并发GC)标记-整理算法

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
应用场景:由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。

在这里插入图片描述

CMS收集器,这款收集器是HotSpot虚拟机中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程同时工作。不幸的是,CMS作为老年代的收集器,却无法与JDK 1.4.0中已经存在的新生代收集器Parallel Scavenge
配合工作,所以在JDK 1.5中使用CMS来收集老年代的时候,新生代只能选择ParNew或者Serial收集器中的一个。

7.G1收集器—jdk11/(默认的垃圾回收器)

G1(Garbage First)垃圾回收器是用在heap memory很大的情况下,把heap划分为很多很多的region块,然后并行的对其进行垃圾回收。如图:
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值