Java中的垃圾回收机制(GC)

一、如何判断是否进行回收?

我们都知道java有自己的垃圾回收机制,可以保证我们的程序运行,那么如何判断某一对象需要回收,哪些不需要呢?
大致就是两种方法
(1)引用计数法:运用一个计数器,有地方引用计数器就加一,有一个引用失效,计数器就减一。
但它也有缺点:很难解决循环引用的问题。
(2)可达性分析算法(GC Root):其基本思路是通过一系列名为”GC Root“的对象作为起始点,从被称为GC Root的对象向下搜索,如果一个对象到GC Root没有任何引用链相连时,则说明此对象不可用。

二、GC Root包括哪些

(1)虚拟机栈中引用的对象
(2)方法区中类静态属性引用的对象
(3)方法区中常量引用的对象
(4)本地方法栈中JNI引用的对象
在这里插入图片描述

三、四大类垃圾收集器

1.串行垃圾回收器(Serial):为单线程环境设计且只使用一个线程进行垃圾回收,会暂停所有的用户线程。不适合服务器环境
2.并行垃圾回收器(Parallel):多个垃圾收集线程并行工作,此时用户线程时暂停的,适用大数据处理首台处理等弱交互场景(多个线程回收,速度加快,jdk8默认)
3.并发垃圾回收器(CMS):用户线程和垃圾收集线程同时执行(交替),不需要停顿用户线程,互联网公司多用此方法
4.G1垃圾回收器:将堆内存分割成不同的区域然后并发地对其进行垃圾回收

四、四大垃圾回收算法

1.复制算法:将内存容量分为两块,每次只是用其中一块,当一块的内存用完时,将还存活的对象复制到另一半上,再将原来的那半进行清除
缺点:浪费内存
在这里插入图片描述
2.标记清除算法:首先标记出所有需要回收的对象,在标记完成后统一回收。
缺点:会产生大量内存碎片
在这里插入图片描述
3.标记整理算法:首先标记出所有需要回收的对象,让所有存活的对象向一端移动,然后清理掉端边界以外的内存
缺点:需要移动,耗时
在这里插入图片描述
4.分代回收算法:把堆内存分为新生代和老年代,新生代又分为 Eden 区、From Survivor 和 To Survivor。一般新生代中的对象基本上都是朝生夕灭的,每次只有少量对象存活,因此采用复制算法,只需要复制那些少量存活的对象就可以完成垃圾收集;老年代中的对象存活率较高,就采用标记-清除和标记-整理算法来进行回收。
在这里插入图片描述

五、七大垃圾收集器

(连线表示可搭配使用)
在这里插入图片描述
新生代
Serial收集器:串行回收(新生代使用复制算法,老年代使用标记整理算法)

Serial/Serial Old收集器

ParNew收集器:新生代用并行回收(新生代使用复制算法,老年代使用标记整理算法)

ParNew/Serial Old收集器
在这里插入图片描述
Parallel Scavenge收集器:新生代用并行回收(新生代使用复制算法,老年代使用标记整理算法)
与ParNew的区别在于可达到一个可控制的吞吐量
Parallel Scavenge/Parallel Old收集器
在这里插入图片描述
老年代
Parallel Old收集器:配合Parallel Scavenge收集器,在老年代也用并行
CMS收集器(并发标记清除收集器):可以与用户线程一起执行,与ParNew配合使用,使用标记清除算法,步骤如下
(初始标记:工作线程会暂停但时间极短;
并发标记:工作线程不停,和用户线程一起工作;
重新标记:修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那部分对象的标记记录,需要
暂停所有的工作线程;
并发清除:工作线程不停,和用户线程一起执行)在这里插入图片描述

G1收集器:G1整体上采用标记-整理算法,局部会采用复制算法

在这里插入图片描述
步骤:初始标记,并发标记,最终标记,筛选回收(需要停止用户线程)
改变:Eden,Survivor和Tenured内存区域不再是连续的,而是变成了大小一样的region,每个region不一定属于某个代,会切换。但逻辑上还是保留了年轻代和年老代(多了Humongous区)
优点:能与应用程序并发执行,整理空闲空间更快,不需要更大的Java Heap,避免全内存扫描,减少内存碎片
在这里插入图片描述
在这里插入图片描述

上述特点总结如下:
在这里插入图片描述

发布了24 篇原创文章 · 获赞 0 · 访问量 598

猜你喜欢

转载自blog.csdn.net/weixin_43896829/article/details/104597069