垃圾回收

什么是垃圾回收

垃圾回收(Garbage Collection,GC),主要是针对堆内存中无效的对象进行回收,释放空间,防止内存泄漏。

垃圾回收,需要关注两点:
第一点:如何判断为垃圾对象;
第二点:如何回收,指的就是回收算法;

查看垃圾回收信息,在 Run Configurations 的 Arguments 加上如下参数就可看到回收日志。

-verbose:gc -XX:+PrintGCDetails

第一部分,如何判定垃圾对象

1.引用计数法

在对象(头)中添加一个引用计数器,当有地方引用这个对象的时候,引用计数器的值就 +1,当引用失效的时候,计数器的值就 -1。

所以当对象的计数器为 0 时,该对象是可回收的。

但此算法有一个缺陷,当两个或多个对象内互相引用时,这些对象无法被回收。

public class Test1 {
	
	public Object obj;

	public static void main(String[] args) {
		Test1 a = new Test1();
		Test1 b = new Test1();
		
		a.obj = b;
		b.obj = a;
		a = null;
		b = null;
		System.gc();
		
	}
}

在这里插入图片描述
a 指向 X011 地址的对象里面有个 obj 成员变量,指向 X012 的对象;
b 指向 X012 地址的对象里面有个 obj 成员变量,指向 X011 的对象;
所以这两个堆里边的两个对象互相引用了,此时两个对象的计数器都是 2。

当 a 和 b 都置为空时,上图 1 和 2 的引用就断了,此时计数器都是 1。
由于两个对象一直互相引用,所以永远不会被回收。

2.可达性分析法

可达性分析法是指,通过一些被称为根节点(GC Roots) 作为起点,从这些根节点开始向下搜索,搜索走过的路径被称为引用链(Reference Chain)。当一个对象到 GC Roots 没有任何引用链相连时(即从 GC Roots 节点到该节点不可达),则证明该对象是不可用的。
在这里插入图片描述
a 作为根节点,一层层往下找,能找到引用的对象,说明对象是存活的,这条查找路径称之为引用链(上图a->X014 的路径称为引用链)。而 X015 没有被任何根节点引用(不可达),所以该对象可以被回收。

可达性分析法解决了引用计数法中无法解决循环引用的问题,只要对象没有直接或间接相连的 GCRoot,这该对象就被认为可回收。

哪些可以作为GCRoot

1.虚拟机栈
2.方法区的类(静态)属性所引用的对象
3.方法区中常量所引用的对象
4.本地方法栈中引用的对象


第二部分,如何回收

1.回收策略

①标记-清除算法

将可回收的对象进行标记,然后清除。
在这里插入图片描述

此算法有两大问题,一是效率问题,二是空间问题。
被标记的对象被清除的时候,堆内存空间产生很多不连续的空间。
当要在堆内存开辟一个很大的空间的时候,需要不断寻址找到可以足够大的空间,这会影响到性能。如果没有找到足够大的空间,那么就需要再次触发垃圾回收,再进行回收,这也会影响到性能。

②复制算法

在这里插入图片描述
将内存空间分为上下两部分,首先将对象存放在上方区域,下方区域内无任何对象。

在这里插入图片描述
垃圾回收器将标记的对象回收,然后将存活的对象有序地复制到下方区域,上方区域就是空的。
接着有创建新的对象的时候,就会在下方区域开辟空间。
然后再发生垃圾回收的时候,就会将存活的对象复制到上方,一直这样循环使用。

复制算法解决了标记清除算法中空间不连续的问题。但是复制算法有一个缺点就是空间利用率不高,因为它需要将空间一分为二。

如果整个堆内存用这个算法回收的话,那么就会有 50% 的空间是空闲的,空间利用率不高。所以此算法中用于 Survivor 区。
Survivor 占用 20% 的空间,分为两块,也只是浪费 10% 的空间。

③标记-整理算法

此算法其实是标记-整理-清除,常用于需回收的内存不多的空间,例如老年代。

此算法比 ① 算法多了整理,该算法会将不需要回收的内存移向内存的一段,需要回收的移向另一端。
在这里插入图片描述
需要回收的移向右侧,不需要回收的移向左侧,这就是整理的过程,清除只需要清除右侧空间就可以了,大大提升了回收效率。

此算法解决了内存碎片的问题,也规避了复制算法只能使用一半空间区域的弊端,但是由于此算法需要对内存中的所有对象进行移动整理,是很耗费时间的。

④分代收集算法

此算法是标记整理算法和复制算法的结合

我们都知道内存分为新生代和老年代,针对新生代和老年代不同的特点,就采用分代收集算法。

分代收集算法根据内存的分代选择不同的垃圾回收算法。

也就是说,它会根根据新生代这种内存回收率较高的区域,选择复制算法;对于老年代或者内存回收率较低的区域,则选择标记整理算法。

2.垃圾收集器

①Serial

最基本,发展最悠久
单线程垃圾收集器
桌面应用

②Parnew

Serial 是单线程的,它是多线程的

③Parallel

复制算法(新生代收集器)
多线程收集器
达到可控制的吞吐量

-XX:MaxGCPauseMillis 垃圾收集器最大停顿时间
-XX:GCTimeRatio 吞吐量大小 (0,100)

吞吐量:CPU用于运行用户代码的时间 与 CPU 消耗的总时间的比值。
吞吐量 = 执行用户代码时间 /( 执行用户代码的时间 + 垃圾回收所占用的时间)

④Cms

Concurrent Mark Sweep

工作过程:
1.初始标记
2.并发标记
3.重新标记
4.并发处理

优点:并发收集、低停顿

缺点:占用大量的CPU资源、无法处理浮动垃圾、出现 Concurrent Mode Failure、空间碎片

⑤G1

优势:并行于并发、分代收集、空间整合、可预测的停顿

工作过程:
1.初始标记
2.并发标记
3.最终标记
4.筛选回收

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值