JVM:Garbage Collection GC

Garbage Collection GC

不管去哪里,都要记得这个图咯。今天重点看看GC垃圾回收是怎么搞的😄😄😄
由于回收的主要区域是堆内存,我们需要重新看看堆内存到底是怎么样子的

堆内存🌲


在这里插入图片描述

  • Young Generation Survivor Space:新生代,包括了Eden Space ,S0,S1区域
    💰Eden Space:最开始的对象都分配在这里,静静等待着垃圾回收
    💰S0:即Survivor0 space,当Eden Space垃圾回收后存活的对象放到这里来
    💰S1:当S0区域的对象逃过了GC的魔掌就会移到S1区域
  • Old Generation tenured:老年代,或者旧生代,主要是Young Generation的对象还没有被回收就会移到这个老年代来了。
  • Permanent Generation:俗称永久代,JDK1.8里面已经把它从堆区域移除了,成为了方法区,用来存储常量,类信息等等

垃圾回收流程📖


在这里插入图片描述

这个就和上面介绍的差不多,总之就是Eden->S0->S1->Tenured
说的那么多,好像说的那么爽,结果没有一个点能够卡得上,到底什么是垃圾啊

什么是垃圾👀


主要有两种方式来判别是不是垃圾:引用计数法和可达性分析。java采用了可达性分析法
引用计数法

引用计数法:引用计数算法是垃圾回收器中的早起策略,在这种方法中,堆中的每个对象实例都有一个引用计数器,点一个对象被创建时,且该对象实例分配给一个变量,该变量计数设置为1 ,当任何其他变量赋值为这个对象的引用时,计数加1 ,(a=b ,则b引用的对象实例计数器+1)但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数器减1,任何引用计数器为0 的对象实例可以当做垃圾收集。 当一个对象的实例被垃圾收集是,它引用的任何对象实例的引用计数器减1.
但是呢,引用计数有个致命的问题,就是不能解决循环引用的实例,比如A引用了B,B引用了A,连个计数永远不为0,那么两个对象永远不会回收

可达性分析

可达性分析:这是java里面采用的方法。该方法的基本思想是通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。
在这里插入图片描述
呐,就从这个图的GC Root开始找,根据离散数学里面的图一样,有很多的GC Root
GC Root:
1.虚拟机栈中引用的对象(本地变量表)
2.方法区中静态属性引用的对象
3. 方法区中常量引用的对象
4.本地方法栈中引用的对象(Native对象)

关于这种引用有四种,强引用,软引用,弱引用,虚引用

强引用: 是java中最强的引用,可以直接访问指向的对象,有点儿像C里面的指针,但是它宁愿抛出OOM,也不愿意去回收,所以可能会导致内存泄露。
软引用: 仅次于强引用,当内存资源使用紧张时才会去回收
弱引用: 弱引用是一种比软引用较弱的引用类型。在系统GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收。在java中,可以用java.lang.ref.WeakReference实例来保存对一个Java对象的弱引用。
虚引用: 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,销毁这个对象,将这个虚引用加入引用队列。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

finalize方法


在这里插入图片描述
在这里插入图片描述
引用了别人的图片:看看

在这里插入图片描述

垃圾回收算法🦢


1⃣️.Mark-Sweep(标记-清除)算法

在这里插入图片描述

分为了两个阶段:第一个阶段就是将要回收的对象标记。第二个阶段就是将标记的对象回收。看似很简单,但是很大的问题,就是内存碎片了。

在这里插入图片描述

2⃣️.Copying(复制)算法
可以说,是为了解决上面的内存碎片的问题把。把堆内存分成了两部分,一部分是分配对象,另一部分留着复制。当要回收的时候,先将还存活的对象复制到另一半,然后一次性清除原来的一半。但是呢,这样我们能够使用的内存就只有一半了,另一半根本使用不了,只能留着复制,而且每次复制都移动那么多对象,效率明显会下降。

在这里插入图片描述

3⃣️.Mark-Compact(标记-整理)算法
这个方法是为了解决Copy算法内存使用问题,它是进行垃圾回收后,再把存活的对象往一边移动,这样子就可以使用整个内存了

在这里插入图片描述

4⃣️.Generational Collection(分代收集)算法
这是大部分JVM常用的一种垃圾回收算法。首先要看到上面那个堆Heap区域的图,所以需要先明白Heap区域分成了Young Generation(Eden,S0,S1),Old Generation。
可以看到在Young Generation,将内存区域分成了几块,很明显就可以使用Copy算法,也就是说Generational Collection采用了上面三种的某几种算法,结合而成的。在Young Generation,这样子在Eden区域的存活的对象复制到S0,然后将Eden区域给清除掉。同理S0存活的对象复制到S1,然后将S0清除。S1存活的复制到老年代Old Generation ,然后清除S1.

在这里插入图片描述

Young Generation触发的GC叫做Minor GC,发生频率比较高,而Old Generation叫做Major GC即Full GC,一般发生频率比较低,因为都是存活率很久的对象

在这里插入图片描述

垃圾收集器🆚


主要的垃圾收集器有四种:

  • Serial Garbage Collection:串行垃圾回收器
  • Parallel Garbage Collection:并行垃圾回收器
  • CMS Garbage Collection:CMS垃圾回收其
  • G1 Garbage Collection:G1垃圾回收器
    在这里插入图片描述

Serial Garbage Collection:一次只开一个线程回收,在垃圾回收时会停止所有的应用程序线程,不然怎么会叫串行呢,对吧,看上图最左边,应用程序线程停止了,只有垃圾回收线程在执行。-XX:+UseSerialGCJVM参数以使用串行垃圾收集器。
Parallel Garbage Collection:上图中间的那个,多个线程执行垃圾回收,是JVM默认的方式,但是也会暂停其他应用程序线程
CMS:并发标记清除(CMS)垃圾收集器使用多个线程扫描堆内存,以标记要逐出的实例,然后清除标记的实例。CMS垃圾收集器只保存以下两种情况下的所有应用程序线程:

  • 在Old Generaton空间中标记引用对象时。
  • 2:如果在执行垃圾收集时堆内存发生并行更改。
    与并行垃圾收集器相比,CMS收集器使用更多的CPU来确保更好的应用程序吞吐量。如果我们可以分配更多的CPU以获得更好的性能,那么CMS垃圾收集器是优于并行收集器的首选。打开XX:+USeParNewGC JVM参数以使用CMS垃圾收集器
    G1 Garbage Collection:G1垃圾收集器用于大型堆内存区域。它将堆内存分成多个区域,并在这些区域内并行进行收集。G1也会在回收内存后压缩空闲堆空间。但是CMS垃圾收集器压缩了stop-the-world(STW)情况下的内存。G1收集器首先根据大多数垃圾对区域进行优先级排序。打开–XX:+UseG1GC JVM参数以使用G1垃圾收集器。
虽然说分成了上面几种,但是呢,根据老年代,新生代又会有不同的使用方式。下图中,Young Generation和Tunured Generation的连线代表可以搭配使用的

在这里插入图片描述

1:Serial收集器(复制Copy算法)

单线程串行运行,会暂停应用程序。算是历史很悠久的一种收集器了。

在这里插入图片描述

2:ParNew收集器(复制Copy算法)

其实就是上面Serial的多线程版本,除了GC线程在多个CPU上同时执行外,其他和Serial没啥区别,也会要暂停其他应用程序

在这里插入图片描述

3:Parallel Scavenge(复制Copy算法)

与吞吐量关系密切,故也称为吞吐量优先收集器。特点:属于新生代收集器也是采用复制算法的收集器,又是并行的多线程收集器(与ParNew收集器类似)。
该收集器的目标是达到一个可控制的吞吐量。还有一个值得关注的点是:GC自适应调节策略(与ParNew收集器最重要的一个区别)

GC自适应调节策略:Parallel Scavenge收集器可设置-XX:+UseAdptiveSizePolicy参数。当开关打开时不需要手动指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRation)、晋升老年代的对象年龄(-XX:PretenureSizeThreshold)等,虚拟机会根据系统的运行状况收集性能监控信息,动态设置这些参数以提供最优的停顿时间和最高的吞吐量,这种调节方式称为GC的自适应调节策略。

Parallel Scavenge收集器使用两个参数控制吞吐量:

  • XX:MaxGCPauseMillis 控制最大的垃圾收集停顿时间
  • XX:GCRatio 直接设置吞吐量的大小。

4:Serial Old收集器(标记整理算法)

在老年代使用的,也是单线程的。使用场景:
  • 在JDK1.5以及以前的版本中与Parallel Scavenge收集器搭配使用。
  • 作为CMS收集器的后备方案,在并发收集Concurent Mode Failure时使用。
    在这里插入图片描述

5:Parallel Old 收集器(标记-整理算法)

是Parallel Scavenge收集器的老年代版本。
特点:多线程,采用标记-整理算法。
应用场景:注重高吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge+Parallel Old 收集器。

Parallel Scavenge/Parallel Old收集器工作过程图:
在这里插入图片描述

6:CMS收集器(标记清除算法)

一种以获取最短回收停顿时间为目标的收集器。
特点:基于标记-清除算法实现。并发收集、低停顿。
应用场景:适用于注重服务的响应速度,希望系统停顿时间最短,给用户带来更好的体验等场景下。如web程序、b/s服务。
CMS收集器的运行过程分为下列4步:

  • 初始标记:标记GC Roots能直接到的对象。速度很快但是仍存在Stop The World问题。
  • 并发标记:进行GC Roots Tracing 的过程,找出存活对象且用户线程可并发执行。
  • 重新标记:为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录。仍然存在Stop The World问题。
  • 并发清除:对标记的对象进行清除回收。

CMS收集器的内存回收过程是与用户线程一起并发执行的。
在这里插入图片描述

CMS收集器的缺点:

  • 对CPU资源非常敏感。
  • 无法处理浮动垃圾,可能出现Concurrent Model Failure失败而导致另一次Full GC的产生。
  • 因为采用标记-清除算法所以会存在空间碎片的问题,导致大对象无法分配空间,不得不提前触发一次Full GC。

7:G1收集器

特点如下:

  • 并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿时间。部分收集器原本需要停顿Java线程来执行GC动作,G1收集器仍然可以通过并发的方式让Java程序继续运行。
  • 分代收集:G1能够独自管理整个Java堆,并且采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。
  • 空间整合:G1运作期间不会产生空间碎片,收集后能提供规整的可用内存。
  • 可预测的停顿:G1除了追求低停顿外,还能建立可预测的停顿时间模型。能让使用者明确指定在一个长度为M毫秒的时间段内,消耗在垃圾收集上的时间不得超过N毫秒。
    在这里插入图片描述
上面简单介绍了一些垃圾回收的基础,后面会详细的分析垃圾收集器并配置实操
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小满锅lock

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值