垃圾回收机制可以自动回收不用的对象,避免内存泄漏问题。
垃圾回收机制主要针对堆区,回收的单位是对象
目录
JVM垃圾回收机制如何判断对象是垃圾
1. 可达性分析
可达性分析指将堆中的对象以树形结构构建起来,然后周期性的遍历,如果某个节点遍历不到,那么则为不可达,也就是垃圾,进入回收机制。
2. 树形结构遍历要有根节点,谁为根节点?
要作为根节点,那么它必定会长时间的存在。所以一般都是在虚拟机栈、本地方法栈和方法区中设置根节点,也称为 GC roots。
- java虚拟机栈中引用的对象
- 本地方法栈中引用的对象
- 方法区类静态属性引用的对象
- 方法区常量引用的对象 (static final 修饰的引用)
3. 可达性分析法的缺点:
- 耗时,遍历结点耗时。
-
STW(stop the world)问题,全程暂停用户应用程序,保证节点的引用不发生改变。
4. 除了可达性分析法来判断垃圾,还有一种但是不被JVM所使用方法,引用计数法
引用计数正如字面意思,把对象的引用数量统计起来,当数量为0时,则视为垃圾。
引用计数法的缺点:
- 耗空间,需要额外的空间计数。
- 循环引用问题,比如两个对象相互引用,无其他引用,对象 A 想被视为垃圾则要对象B解除引用,而对象B解除引用则要A解除引用,类似于死锁。(46条消息) 【多线程】-- 死锁_hello Jimmy的博客-CSDN博客
常见的垃圾回收算法
1. 标记-清除算法(Mark and Sweep):先遍历程序中所有存活的对象并打上标记,然后清除所有没有标记的对象。
- 优点是可以处理任何存活对象之间的关系;
- 缺点是会产生大量的不连续的内存碎片,影响内存分配效率。
2. 复制算法(Copy):先要将空间划分为两份,将存活对象从一个内存区域复制到另一个内存区域,然后清除原来的内存区域。
- 优点是避免了内存碎片的问题;
- 缺点是需要额外的空间来进行复制,且无法处理大对象的情况。
3. 标记-整理算法(Mark and Compact):先标记所有存活对象,然后将它们向一个内存区域移动,然后清除整个原内存区域,类似于顺序表删除元素。
- 优点是可以处理任何存活对象之间的关系,且无需额外的内存空间。
- 缺点是它也存在移动对象的成本问题。
4. 分代算法(Generational):将内存区域分为新生代和老年代,针对不同年代的对象采用不同的垃圾回收算法。新生代中存活时间短的对象采用复制算法,而老年代中存活时间长的对象采用标记-整理算法。
分代算法兼顾了复制算法和标记-整理算法的优点,且针对不同年龄段的对象采用不同的垃圾回收算法,提高了效率。
不同的垃圾回收算法适用于不同的场景,选择合适的算法可以提高垃圾回收的效率。
JVM垃圾回收算法
分代算法:将内存区域分为新生代和老年代,针对不同年代的对象采用不同的垃圾回收算法。
注意:“将内存区域分为新生代和老年代”,这个内存区域是?正如文章开头所说垃圾回收机制针对的是堆区,所以堆区的结构就是这样。
新生代和老年代
新生代区采取复制算法,那么就意味着新生代区是被划分为两个区域的,这两个区域分别是伊甸区和幸存者区,将存活对象从伊甸区域复制到幸存者内存区域,然后清除伊甸区域的对象。值得注意的是,幸存者区也要经历垃圾回收,多次未被回收的对象会转移到老年区,幸存者区采取的垃圾回收算法也是复制算法,也就同样意味着有两个区域,这两个区域分别是S1区和S2区。
老年代采取标记-整理算法,因为老年代的对象是经历很多次的可达性分析,所以他们被回收的概率是相对低的,所以这个区域的分析频率会降低,即使被视为垃圾,移动的成本不会很高。注意如果是比较大的对象会直接到老年代。
参考:JVM基础(二)JVM的内存分区 - 知乎 (zhihu.com)