Java虚拟机二:垃圾回收机制

本文详细介绍了Java虚拟机的垃圾回收机制,包括如何确定可回收对象(引用计数算法与可达性分析算法)、常见的垃圾回收算法(标记清除、复制、标记整理、分代收集)以及各种垃圾收集器的特点,如Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS和G1。文章探讨了各种算法和收集器的优缺点,强调了垃圾回收对于系统性能和内存管理的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇说了Java运行时的内存区域及对象的创建,本文将说垃圾回收器及内存分配,上一篇文章链接 Java虚拟机一:Java运行时内存区域及对象的创建

[声明]Java虚拟机设计的知识点主要来源于周志明先生的深入理解Java虚拟机

本文将根据三个方面来描述垃圾回收机制:

一、如何确定哪些是要回收的对象
二、垃圾回收算法思想
三、垃圾收集器

一、如何确定哪些是要回收的对象

1.1。引用计数算法 :

引用计数算法就是给对象添加一个引用计数器,每当有一个地方引用该对象的时候就会+1,相反当失去一个引用的时候就-1,当引用数为0的时候也就说明这个对象不在被使用就可以被回收。这种算法实现简单,效率也很高,但是唯一的缺点就是在两个对象相互引用的时候那么他们的引用就不会为0,那么GC也就无法回收他们,

例子:

public class GcTest {
    public Object instance = null;

    public static void testGC() {

        GcTest objA = new GcTest();//第一步,实例1

        GcTest objB = new GcTest();//第二步,实例2

        objA.instance = objB;//第三步

        objB.instance = objA;//第四步

        objA = null;//第五步

        objB = null;//第六步

    }
}

上面的例子中内存是不会被回收的,这个例子也被广泛的流传,但是又是否真的理解了为什么不能被回收呢?下面我们分析一下为什么:
1。第一步,GcTest 触发了new操作,在栈中创建objA的引用,在堆中创建了GcTest的实例,那么这个时候GcTest的实例1引用数 = 1,被objA引用;

2。第二步,GcTest 触发了new操作,在栈中创建objA的引用,在堆中创建了GcTest的实例,那么这个时候GcTest的实例2引用数 = 1,被objB引用;

3。第三步,GcTest实例2的引用 = 2,因为他的实例又被实例1引用了

4。第四部,GcTEst实例1的引用 = 2,因为他的实例又被实例2引用了

5。第五步,这个时候实例1的引用变为了 = 1,因为置null后,这时候实例1只是失去了栈中objA的引用

6。第六步,这个时候实例2的引用变为了 = 1,因为置null后,这时候实例2只是失去了栈中objB的引用

那么我们也就清楚了,这个时候虽然我们的实例1和实例2都不再使用,但是因为它们两个的循环互相引用,那么GC是没办法对它们回收的。这也就是引用计数算法最大的缺点

1.2。可达性分析算法 :

可达性分析算法是以一系列可以成为GC Roots的对象的节点向下搜索,搜索所走的路径称之为引用链,当一个对象没有任何一条引用链和GC Roots相连的时候,那么就认为这个对象是可以被回收的。

可以被称之为GC Roots的对象有:

虚拟机栈(栈帧中的本地变量表)中引用的对象;

方法区中类静态属性引用的对象;

方法区中常量引用的对象;

本地方法栈中JNI(即一般说的Native方法)引用的对象;

总结就是,方法运行时,方法中引用的对象;类的静态变量引用的对象;类中常量引用的对象;Native方法中引用的对象。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值