一次性把GC讲清楚
垃圾收集 GC(Garbage Collection)是 Java 非常重要的核心技术之一,Java 开发中程序员不需要关心对象的内存分配和资源释放,这些都由 GC 来完成,这使得 Java 开发者只需要将注意力集中在业务逻辑的处理上。
学习 GC 需要从以下 4 个方面入手:
1、如何判断某个对象是垃圾,需要被回收?
2、垃圾回收算法。
3、不同内存区域的回收方式。
4、垃圾收集器的分类。
如何判断对象是垃圾
Java 对象被判定为垃圾的标准:没有被其他对象引用,判断方法有两种:
1、引用计数算法
通过判断对象的引用数量来决定是否要被回收,每一个对象实例都有一个计数器,被引用则+1,完成引用则-1。
什么是完成引用?
当该对象的引用超过了生命周期,或者引用指向了其他对象,在某方法中定义一个对象的引用变量,方法结束之后变量被虚拟机栈自动释放,则改对象的引用也就结束了,所以任何一个引用计数为 0 的对象是可以被当作垃圾回收的。
2、可达性分析算法
通过判断对象的引用链是否可达来决定对象是否要被回收,这个算法的基本思想就是通过一系列的称为 GC Root 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Root 没有任何引用链相连的话,则证明此对象是不可达的,即认为它不可用,如下图所示。
什么对象可以作为 GC Root ?
1、虚拟机栈中的引用对象
2、方法区中的常量引用对象
3、方法区中的类静态属性引用对象
4、本地方法栈中的引用对象
5、活跃线程中的引用对象
垃圾回收算法
1、标记-清除算法(Mark and Sweep)
标记:从根集合进行扫描,对存活的对象进行标记。
清除:对堆内存进行遍历,回收不可达对象内存。
缺点:清除后会产生大量不连续的内存碎片,可能导致后续在创建较大对象是无法找到足够的连续内存而触发再一次的垃圾回收,如下图所示。
2、复制算法
将可用内存分为对象面和空闲面,在对象面上创建对象,当对象面没有空间的时候,将还存活的对象复制到空闲面,将对象面所有对象清除。
解决了碎片化问题,顺序分配内存,简单高效,适用于对象存活率较低的场景,因为复制的内容少,所以效率高,如下图所示。
3、标记-整理算法
标记:从根集合进行扫描,对存活的对象进行标记。
清除:移动所有存活的对象,按内存地址依次排列,然后将末端地址以后的内存全部回收。
在标记-清除的基础上完成了移动,解决了内存碎片的问题,但是成本更高,适用于对象存活率较高的场景,如下图所示。
4、分代收集算法
是一种组合的回收机制,也是 GC 的主流回收算法,将不同生命周期的对象分配到堆中的不同区域,采用不同的垃圾回收算法,提高 JVM 垃圾回收效率。
不同内存区域的回收方式
年轻代
使用 Minor GC 进行回收,采用复制算法,年轻代分为 Eden 区和 Survivor 区。
Eden区:对象刚被创建的时候,存放在 Eden 区,如果 Eden 区放不下,则放在 Survivor 区,甚至老年代中。
Survivor 区:Minor 回收时使用,将 Eden 中存活的对象存入 Survior 中(From),再一次 Minor 时,将 Survior From 中的对象存入 Survior To 中,清除 Survior From ,下一次 Minor 时重复次步骤,Survior From 变成 Survior To,Survior To 变成 Survior From,依次循环,同时每次 Minor,对象的年龄都 +1,年龄增加到一定程度的对象,移动到老年代中。
老年代
存放生命周期较长的对象,使用标记-清理算法或者标记-整理算法进行回收。
垃圾收集器的分类
年轻代常见的垃圾收集器
1、Serial 收集器(复制算法):单线程收集,进行垃圾收集时,必须暂停所有工作线程。
2、ParNew 收集器(复制算法):多线程收集,垃圾收集和工作线程可同时执行。
3、Parallel Scavenge 收集器(复制算法):多线程收集,更关注系统的吞吐量。
Serial 收集器和 ParNew 收集器更关注用户线程停顿时间,停顿时间越短,响应速度越快,用户体验越好,适用于直接与用户交互的程序。
Parallel Scavenge 收集器更关注系统的吞吐量,可提升 CPU 的效率,尽快完成运算任务,适合在后台运行,不需要太多交互的程序。
吞吐量 = 运行用户代码的时间/(运行用户代码的时间 + 垃圾收集的时间),即 CPU 运行用户代码时间与 CPU 总消耗时间的比值。
老年代常见的垃圾收集器
1、Serial Old 收集器(标记-整理算法):单线程收集,进行垃圾收集时,必须暂停所有工作线程。
2、ParNew Old 收集器(标记-整理算法):多线程收集,垃圾收集和工作线程可同时执行,吞吐量优先。
3、CMS 收集器(标记-清除算法):垃圾回收线程和用户线程几乎可以同时工作。
4、Garbage First 收集器(复制+标记-整理算法):并发和并行,使用多个 CPU 来缩短 Stop-the-World 的停顿时间,与用户线程并发执行,并且可采用不同的方式去处理新产生的对象。同时有利于空间整合,基于标记-整理算法,可以解决内存碎片的问题。
Stop-the-World:JVM 由于要执行 GC 而停止了应用程序的执行。
任何一种 GC 算法中都会发生,当 Stop-the-World 发生时,除了 GC 的线程以外, 所有线程都处于等待状态,直到 GC 任务完成,多数 GC 优化就是通过减少 Stop-the-World 发生的时间来提高程序性能。
以上就是 GC 的核心内容,你都学会了吗?
转载自:GC线程