【JVM】垃圾回收算法

有哪些常见的垃圾回收算法?

1.1960年John McCarthy发布了第一个GC算法:标记-清除算法。

2.1963年Marvin L. Minsky 发布了复制算法。

3.标记--整理算法

4.分代GC算法

标记清除算法

什么是标记清除算法?

标记清除算法的核心思想分为两个阶段:
1.标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出所有存活对象。
2.清除阶段,从内存中删除没有被标记也就是非存活对象**。**

标记清除算法的优缺点

优点:实现简单,只需要在第一阶段给每个对象维护标志位,第二阶段删除对象即可。

缺点:1.碎片化问题由于内存是连续的,所以在对象被删除之后,内存中会出现很多细小的可用内存单元。如果我们需要的是一个比较大的空间,很有可能这些内存单元的大小过小无法进行分配。

2.分配速度慢。由于内存碎片的存在,需要维护一个空闲链表,极有可能发生每次需要遍历到链表的最后才能获得合适的内存空间。

复制算法

什么是复制算法

复制算法的核心思想是:

1.准备两块空间From空间和To空间,每次在对象分配阶段,只能使用其中一块空间(From空间)

2.在垃圾回收GC阶段,将From中存活对象复制到To空间。

3.将两块空间的From和To名字互换。

复制算法的优缺点

优点

吞吐量高 :复制算法只需要遍历一次存活对象复制到To空间即可,比标记-整理算法少了一次遍历的过程,因而性能较好,但是不如标记-清除算法,因为标记清除算法不需要进行对象的移动

不会发生碎片化:复制算法在复制之后就会将对象按顺序放入To空间中,所以对象以外的区域都是可用空间,不存在碎片化内存空间.

缺点

内存使用效率低:每次只能让一半的内存空间来为创建对象使用

标记整理算法

什么是标记清除算法

标记整理算法也叫标记压缩算法,是对标记清理算法中容易产生内存碎片问题的一种解决方案。

核心思想分为两个阶段:

1.标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出所有存活对象。

2.整理阶段,将存活对象移动到堆的一端。清理掉存活对象的内存空间。

标记整理算法的优缺点

优点

内存使用效率高:整个堆内存都可以使用,不会像复制算法只能使用半个堆内存

不会发生碎片化:在整理阶段可以将对象往内存的一侧进行移动,剩下的空间都是可以分配对象的有效空间

缺点

整理阶段的效率不高:整理算法有很多种,比如Lisp2整理算法需要对整个堆中的对象搜索3次,整体性能不佳。可以通过TwoFinger、表格算法、ImmixGC等高效的整理算法优化此阶段的性能

分代垃圾回收算法

什么是 分代垃圾回收算法

现代优秀的垃圾回收算法,会将上述描述的垃圾回收算法组合进行使用,其中应用最广的就是分代垃圾回收算法(Generational GC)。分代垃圾回收将整个内存区域划分为年轻代和老年代:

分代回收时,创建出来的对象,首先会被放入Eden伊甸园区。
随着对象在Eden区越来越多,如果Eden区满,新创建的对象已经无法放入,就会触发年轻代的GC,称为Minor GC或者Young GC。Minor GC会把需要eden中和From需要回收的对象回收,把没有回收的对象放入To区。

接下来,S0会变成To区,S1变成From区。当eden区满时再往里放入对象,依然会发生Minor GC。此时会回收eden区和S1(from)中的对象,并把eden和from区中剩余的对象放入S0。

注意:每次Minor GC中都会为对象记录他的年龄,初始值为0,每次GC完加1。

如果Minor GC后对象的年龄达到阈值(最大15,默认值和垃圾回收器有关),对象就会被晋升至老年代。

当老年代中空间不足,无法放入新的对象时,先尝试minor gc如果还是不足,就会触发Full GC,Full GC会对整个堆进行垃圾回收。

如果Full GC依然无法回收掉老年代的对象,那么当对象继续放入老年代时,就会抛出Out Of Memory异常。

分代垃圾回收算法优点

程序中大部分对象都是朝生夕死,在年轻代创建并且回收,只有少量对象会长期存活进入老年代。分代垃圾回收的优点有:

1、可以通过调整年轻代和老年代的比例来适应不同类型的应用程序,提高内存的利用率和性能。

2、新生代和老年代使用不同的垃圾回收算法,新生代一般选择复制算法效率高、不会产生内存碎片,老年代可以选择标记-清除和标记-整理算法,由程序员来选择灵活度较高。

3、分代的设计中允许只回收新生代(minor gc),如果能满足对象分配的要求就不需要对整个堆进行回收(full gc),STW(Stop The World)由垃圾回收引起的停顿时间就会减少。

相关推荐
元气代码鼠2 分钟前
C语言程序设计(进阶)
c语言·开发语言·算法
十雾九晴丶36 分钟前
攻防世界--->gametime
算法
Aurora_th1 小时前
树与图的深度优先遍历(dfs的图论中的应用)
c++·算法·深度优先·图论·dfs·树的直径
懒洋洋大魔王3 小时前
7.Java高级编程 多线程
java·开发语言·jvm
只吹45°风3 小时前
JVM-类加载器的双亲委派模型详解
jvm·类加载器·双亲委派
马剑威(威哥爱编程)3 小时前
除了递归算法,要如何优化实现文件搜索功能
java·开发语言·算法·递归算法·威哥爱编程·memoization
算法萌新——13 小时前
洛谷P2240——贪心算法
算法·贪心算法
湖北二师的咸鱼3 小时前
专题:二叉树递归遍历
算法·深度优先
重生之我要进大厂4 小时前
LeetCode 876
java·开发语言·数据结构·算法·leetcode
KBDYD10104 小时前
C语言--结构体变量和数组的定义、初始化、赋值
c语言·开发语言·数据结构·算法