GC

Garbage Collection ,Java进行启动后创建垃圾回收线程(垃圾回收线程是一个守护线程)

垃圾回收的时机:

(1)显示的调用 System.gc(),此处只是建议 JVM 进行 Full GC,并不是一调用就会调用垃圾回收机制,一般是JVM自己来进行垃圾回收
(2)JVM 垃圾回收机制:
a)创建对象时需要分配内存,如果空间不足,触发 GC
b)其他机制
java.lang.Object 中有一个 finalize() 方法,当 JVM 确定某一个对象没有被引用时,垃圾回收机制就会调用 finalize() 方法,用来标志该对象已经快要被回收了,也就类似于给它贴上了即将死亡的标签,之后就可以回收该对象,如果我们手工调用该方法,不会造成对象被回收

垃圾回收策略–如何判断对象已死亡?

1.可达性分析算法

通过一系列的"GC Roots"对象作为起始点,类似于树种的根节点,往下寻找搜索,把有引用到的节点都收集起来,形成一条条的引用链,也就是说如果有其他变量引用到该节点,那么就证明该对象不能够被回收,如果有对象没有任何引用链连接到,也就是没有其他的变量引用它,那么就证明对象死亡可以回收了

2.引用计数算法

给对象创建一个引用计数器,如果有其他对象引用到它,那么计数器+1,如果引用时效,那么计数器-1,计数器为0时不能被引用了,这样算法实现简单,效率也很高,但是有的语言不适用例如Java,因为会出现循环引用的问题,一个对象引用另一个对象,另一个对象也引用这个对象,那么它们的计数器都+1
这涉及到语言的编译类型:动态语言,静态语言,编译型语言,解释型语言

垃圾回收的区域:

1.方法区/元数据:GC 中称为 永久代

回收内容:无用的常量,废弃的类等,回收的内容很少

2.堆:GC 中称为 GC堆

堆可以细分为:
在这里插入图片描述
(1)对于新生代的垃圾回收:Young GC (简称 YGC)Java 对象具有创建的快死亡的也快的特征,所以在新创建对象到新生代区域,随后很快就会被回收,回收速度快
(2)对于老年代的垃圾回收:Full GC,因为在老年代的数据都是较大的,而且它们存活的时间很长,所以就任务它们不会很快的被回收,这个区域的垃圾回收速度就比新生代的垃圾回收速度慢很多

垃圾回收算法:

1.标志-清除算法(Mark-Sweep):基础的收集算法,老年代收集算法

通过标记需要回收的对象,在之后统一进行回收
存在问题:
a)效率问题:标记和清除的效率都不高
b)空间问题,清除之后会空间内的内存不连续,空间存在碎片式的内存,大对象就没有足够的内存来存放
在这里插入图片描述

2.复制算法(copying ):新生代的算法

新生代内有两个内存大小相同的内存区域 S1 和 S2,当一个内存快要满了,此时把这块内存中存活的对象复制到另一块内存中,然后堆之前的那块内存进行全部清除,这样就可以清理出连续的内存
在这里插入图片描述

3.标记-整理算法(Mark-Compect ):老年代算法

和之前的标志-清除算法基本相同,不同之处在于,它把死亡的对象清除之后,将存活的对象移动到一端,这样就可以整理出连续的内存
在这里插入图片描述

4.分代收集算法

它没有具体的算法实现,只是将之前的三种算法进行整合,按照不同的内存区域使用不同的算法
新生代中:因为在新生代中经常出现对象死亡的情况,所以需要清除的频率高,采取 复制算法
老年代中:存放大对象和存活时间长的对象,所以清除死亡对象的频率低,采取 标志-清除和标志-整理 算法

垃圾回收的过程:

1.新生代垃圾回收过程:
因为新生的死亡对象清除频率高,也就是创建的对象很快就死亡需要清除,所以新生代的内存空间不多,新生代又分为 Eden(这块区域内存较大) 和 To Survivor、From Survivor 区域(这两块内存小,内存大小相同),暂且方便叫这两个内存区域为 S1 和 S2
现在 Eden 内存区是有存活和死亡对象,S1 内存区也是有存活和死亡对象,先将两个内存的存活对象都复制到 S0 区域,然后将两块内存全部进行清理,这里用到了复制算法,一般新创建的对象都会储存再 Eden 区,通过Eden区和Survivor 区的来回复制清除,最终 交换十五次还存活着,那么就存入老年代
在这里插入图片描述

虚拟机的垃圾回收器:
在这里插入图片描述

用户线程:用户程序执行代码的线程
垃圾回收线程:垃圾回收的守护线程

stop-the-world:简称为 stw ,停止世界,垃圾回收线程会在一定的情况下暂替用户线程(基于字节码来执行暂停),用户线程暂替之后只执行垃圾回收线程,这样就可以安全的回收死亡的对象

暂停用户线程的方法:

并不是所有的线程都可以进行垃圾回收,只有跑到安全点的线程才可以进行GC

这其中就涉及到用户体验和吞吐量的问题:
(1)用户体验:如果用户线程暂停的时间越长,那么用户的体验就越差
(2)吞吐量:CPU执行用户线程的时间和CPU执行Java程序的总时间之比,称为吞吐量,吞吐量越大,说明用户执行的时间越长,用户执行的时间越短说明吞吐量越小

减少暂停时间的方法:

牺牲新生代空间和吞吐量:假设原来新生代内存为 600 M,现在设置为 300 M,那么垃圾回收的速度肯定变快了,因为一般的对象都是在创建在新生代的内存上,如果新生代内存空间不够了就会进行垃圾回收,假设原来垃圾回收的速度为:每10 m 一次,每次用户线程暂停 100 m,那么现在垃圾回收次数变多了,就假设变为 每 5 m 回收一次,每次暂停时间为 70 m,所以这就导致虽然回收次数多了,但是总的回收时间边长了,也就导致吞吐量降低了。

新生代的三个垃圾收集器:

Serial收集器(新生代收集器,串行GC):它在进行垃圾回收时,只有一个线程在允许,必须要暂停用户线程,直到它收集结束,这也的缺点也很明显:用户体验差

应用场景:Client 模式下的默认新生代回收器
优点:对于单个CPU效率高,因为没有线程之间交互的开销

ParNew收集器(新生代收集器,并行GC)

Serial收集器的多线程版本,现在CPU都是多核,所以ta它对于GC的资源有效利用率更高,注意:只有这个新生代收集器可以搭配CMS老年代收集器

Parallel Scavenge收集器(新生代收集器,并行GC)

(1)可以多个线程同时执行
(2)采用的是复制算法
(3)可以通过参数来控制吞吐量的大小
(4)可以通过当前的收集情况来,自己调节适应提供合适的停顿时间或者吞吐量
优点:适用于吞吐量优先的情况

老年代的三个垃圾收集器:

Serial Old收集器(老年代收集器,串行GC)

Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用“标记-整理”算法。
主要作用:作为 CMS 收集器的后背方案

Parallel Old收集器(老年代收集器,并行GC)

Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
主要作用:可以和Parallel Scavenge搭配使用

CMS收集器(老年代收集器,并发GC)

可以和用户线程同时执行,但是后面也会涉及到用户线程的暂停情况
是以最短回收停顿时间为目标的收集器,也就是说这个收集器是以用户体验为目标的收集器
特性:
(1)并发收集、低停顿
(2)基于“标记—清除”算法实现的。
整个过程分为4个步骤:

  1. 初始标记(CMS initial mark) 初始标记仅仅只是标记一下GC Roots能直接关联到的对象,
    速度很快, 需要“Stop The World”。
  2. 并发标记(CMS concurrent mark) 并发标记阶段就是进行GC Roots Tracing的过程,不需要暂停用户线程,作用就是继续标记需要回收的对象
  3. 重新标记(CMS remark) 修正一些标记过的对象,因为这些对象可能被其他变量引用了,说明之前标记过要回收的对象现在不需要回收了,仍然需要“Stop The World”。
  4. 并发清除(CMS concurrent sweep) 并发清除阶段会清除对象。
    由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所
    以,从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的
存在的问题:

(1)CMS收集器会抢占CPU的资源:并发的时候不能暂停用户线程,所以就需要更多的其他线程来进行操作
(2)浮动垃圾:在第四个阶段并发清除的时候,因为是并发执行的,这个时候用户线程还会产生垃圾,而且这一部分垃圾之前没有提前标记,所以在第四个阶段无法回收,那么这些垃圾就只能放到下一个部分回收,如果出现这部分垃圾很多造成老年代内存几乎被填满了,那么此时再次进行标记清除时就出现问题了,因为必须要留下一部分内存给用户线程执行,但是现在老年代内存几乎都填满了
解决方法:这个时候就需要启动 Plan B,也就是调用备用方案 Serial Old 垃圾回收器,stw,暂停用户线程,让垃圾回收线程单个执行
(3)标记-清除算法带来的空间碎片问题:导致可用的内存不连续,大对象无法储存
解决方法:设置参数,进行 FULL GC ,对碎片进行整理,这个过程需要暂停用户线程,会导致停顿时间边长,但是CMS收集器的目的是为了降低用户的停顿时间,所以因此又设计了一个参数,设置固定的时间,每隔一段时间对内存碎片进行整理,这样就不用每次都FULL GC

G1收集器(唯一一个老年代和新生代都可以回收的收集器)

将堆分为一个个规则的小板块,每隔板块可用指定内存区域,例如指定 Survivor 内存区域,指定 Eden 内存区域,在整体采用标志-整理的算法,Survivor 区域内采用复制算法
具体回收的步骤和 CMS 都差不多,明显差距的阶段是第二个阶段:并发标记
G1在并发标记的时候,会判断当前对象的存活率是不是很低或者基本没有对象存活,那么这个对象就会被直接的回收掉,不会像CMS一样还进行标记等到后面再回收

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值