垃圾回收算法
【Java虚拟机】JVM垃圾回收机制和常见回收算法原理-腾讯云开发者社区-腾讯云
垃圾回收机制
(1)什么是垃圾回收机制(Garbage Collection, 简称GC)
- 指自动管理动态分配的内存空间的机制,自动回收不再使用的内存,以避免内存泄漏和内存溢出的问题
- 最早是在1960年代提出的,程序员需要手动管理内存的分配和释放
- 这往往会导致内存泄漏和内存溢出等问题,同时也增加了程序员的工作量,特别是C++/C语言开发的时候
- Java语言是最早实现垃圾回收机制的语言之一,其他编程语言,如C#、Python和Ruby等,也都提供了垃圾回收机制
(2)JVM自动垃圾回收机制
- 指Java虚拟机在运行Java程序时,自动回收不再使用的对象所占用的内存空间的过程
- Java程序中的对象,一旦不再被引用会被标记为垃圾对象,JVM会在适当的时候自动回收这些垃圾对象所占用的内存空间
- 优点
- 减少了程序员的工作量,不需要手动管理内存
- 动态地管理内存,根据应用程序的需要进行分配和回收,提高了内存利用率
- 避免内存泄漏和野指针等问题,增加程序的稳定性和可靠
- 缺点
- 垃圾回收会占用一定的系统资源,可能会影响程序的性能
- 垃圾回收过程中会停止程序的执行,可能会导致程序出现卡顿等问题
- 不一定能够完全解决内存泄漏等问题,需要在编写代码时注意内存管理和编码规范
垃圾回收算法
引用计数法
跟踪每个对象被引用的次数,当引用次数为0 的时候,可以将该对象回收。
优点是实现简单,缺点是循环引用没办法回收,而且引用计数器消耗大。
可达性分析算法
- 可达性分析算法的基本思想是通过一系列的“GC Roots”对象作为起点进行搜索。
- 如果“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。
- 被判定为不可达的对象要成为回收对象,要至少经历两次标记过程。
- 如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。
通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用。
什么是GC ROOT
垃圾回收算法之标记-复制算法
- 标记算法是一种常见的垃圾回收算法,它的基本思路是将Java堆分为两个区域:一个活动区域和一个空闲区域
- 在垃圾回收过程中,首先标记所有被引用的对象
- 然后将所有被标记的对象复制到空闲区域中,最后交换两个区域的角色,完成垃圾回收
- 标记复制算法的详细实现步骤
- 将Java堆分为两个区域:一个活动区域和一个空闲区域,初始时,所有对象都分配在活动区域中
- 从GC Roots对象开始,遍历整个对象图,标记所有被引用的对象
- 对所有被标记存活的对象进行遍历,将它们复制到空闲区域中,并更新所有指向它们的引用,使它们指向新的地址
- 对所有未被标记的对象进行回收,将它们所占用的内存空间释放
- 交换活动区域和空闲区域的角色,空闲区域变为新的活动区域,原来的活动区域变为空闲区域
- 当空闲区域的内存空间不足时,进行一次垃圾回收,重复以上步骤。
- 优点
- 如果内存中的垃圾对象较多,需要复制的对象就较少,则效率高
- 清理后,内存碎片少
- 缺点
- 标记复制算法的效率较高,但是预留一半的内存区域用来存放存活的对象,占用额外的内存空间
- 如果出现存活对象数量比较多的时候,需要复制较多的对象 效率低
- 假如是在老年代区域,99%的对象都是存活的,则性能底,所以老年代不适合这个算法
复制过程如下,GC会将五个存活对象复制到to区,并且保证在to区内存空间上的连续性。
最后,将from区中的垃圾对象清除。
垃圾回收算法之标记-整理算法
标记-整理算法(Mark-Compact Algorithm) 是一种常见的垃圾回收(GC)算法,主要用于解决 标记-清除算法(Mark-Sweep) 产生的内存碎片问题。它通常被用于 Java 的老年代(Old Generation)垃圾回收中。
标记-整理算法主要分为两大阶段:
标记阶段(Mark Phase)
和标记-清除算法一样,从 GC Roots 出发,遍历所有可达对象,并将其标记为“存活”状态。
整理阶段(Compact Phase)
将所有存活对象向内存的一端移动(通常是低地址方向)。
移动后会更新对象引用地址,以保证程序继续正确运行。
移动完成后,直接清理边界以后的内存空间。
特点 | 标记-清除算法 | 标记-整理算法 |
---|---|---|
内存碎片 | 会产生碎片 | 不会产生碎片 |
效率 | 清除快(只清除不可达对象) | 较慢(需要移动对象) |
适用场景 | 适用于对象回收率较高的情况 | 适用于对象存活率较高的情况 |
垃圾回收算法之-分代算法
新生代分为eden区、from区、to区,老年代是一整块内存空间
分代算法将内存区域分为两部分:新生代和老年代。
根据新生代和老年代中对象的不同特点,使用不同的GC算法。
新生代对象的特点是:创建出来没多久就可以被回收(例如虚拟机栈中创建的对象,方法出栈就会销毁)。也就是说,每次回收时,大部分是垃圾对象,所以新生代适用于复制算法。
老年代的特点是:经过多次GC,依然存活。也就是说,每次GC时,大部分是存活对象,所以老年代适用于标记压缩算法。