问:JVM当中的垃圾分类怎么搞?

devtools/2024/10/18 13:27:24/

在Java中,JVM(Java虚拟机)的垃圾识别与分类是自动内存管理的重要组成部分。这一过程主要通过垃圾收集器(Garbage Collector)实现,旨在识别和回收不再被程序引用的对象,以释放内存空间。

1. 垃圾识别与分类的基础

在Java中,所谓的“垃圾”是指没有任何引用指向的对象。这些对象虽然仍然占据着内存空间,但已经无法被程序访问和使用。为了识别和回收这些垃圾对象,JVM采用了多种算法和策略。

2. 垃圾识别算法

2.1 引用计数法

引用计数法是一种简单而直观的垃圾收集算法。其核心思想是通过在对象头中添加一个引用计数器,记录该对象被引用的次数。每当有一个新的引用指向该对象时,引用计数加一;当引用被删除或者超出作用范围时,引用计数减一。当引用计数为零时,表示该对象不再被引用,即可以被回收。

然而,引用计数法有一个明显的缺陷,即难以处理循环引用的情况。例如,两个对象互相引用,它们的引用计数永远不会变为零,即使它们已经不再被程序所使用。

示例代码

class ReferenceCountingObject {private int referenceCount = 0;public ReferenceCountingObject() {// 对象初始化时,引用计数为0}public void addReference() {referenceCount++;}public void removeReference() {referenceCount--;if (referenceCount == 0) {// 当引用计数为零时,可以进行垃圾回收操作System.out.println("对象被回收");}}
}public class ReferenceCountingExample {public static void main(String[] args) {// 创建两个对象ReferenceCountingObject obj1 = new ReferenceCountingObject();ReferenceCountingObject obj2 = new ReferenceCountingObject();// obj1引用计数加一obj1.addReference();// obj2引用计数加一obj2.addReference();// obj1引用计数减一obj1.removeReference();// obj1引用计数为零,可以进行垃圾回收// obj2引用计数仍为一}
}
2.2 可达性分析算法

可达性分析是Java虚拟机中垃圾收集的核心算法之一。它主要通过判断对象是否能够从一组称为"GC Roots"的根对象出发,通过引用链追踪,最终判断对象是否可达。GC Roots包括虚拟机栈中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象以及本地方法栈中JNI(Java Native Interface)引用的对象。

可达性分析的过程如下:

  1. 初始标记阶段:STW(Stop-The-World),只标记GC根直接关联的对象,耗时极少。
  2. 并发标记阶段:由GC根依次向下标记所有关联的对象,可达为存活对象,不可达为可回收对象。
  3. 重新标记阶段:STW,标记新建的对象引用(GC收集器通过读写屏障+增量更新记录新建的引用对象)。
  4. 清除标记阶段:GC线程与用户线程并发清理被标记的垃圾对象。

可达性分析算法能够解决引用计数法无法处理的循环引用问题,因此成为当前主流虚拟机采用的垃圾收集算法。

3. 垃圾分类与回收算法

在识别出垃圾对象后,JVM需要采用合适的算法来回收这些对象所占用的内存空间。以下是几种常见的垃圾回收算法:

3.1 标记-清除算法

标记-清除算法是最基础的收集算法。它分为“标记”和“清除”两个阶段:

  1. 标记阶段:标记出所有存活的对象。
  2. 清除阶段:统一回收所有未被标记的对象。

然而,标记-清除算法存在两个明显的问题:

  1. 效率问题:如果需要标记的对象太多,效率不高。
  2. 空间问题:标记清除后会产生大量不连续的碎片。
3.2 复制算法

复制算法将堆内存分割成两块大小相同的区域,每次只使用其中一块进行对象分配。当这一块内存使用完后,就将还存活的对象复制到另一块区域,然后将已使用的内存空间一次清理掉。

复制算法的优点是不会产生内存碎片,但缺点是内存使用效率低,每次只能使用一半的内存空间。

3.3 标记-整理算法

标记-整理算法是对标记-清除算法的优化。它在标记阶段仍然标记所有存活的对象,但在清除阶段不是直接回收对象,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。

3.4 分代收集算法

分代收集算法是当前虚拟机普遍采用的垃圾收集算法。它将堆内存划分为新生代和老年代,根据对象的存活周期选择合适的垃圾收集算法。

  • 新生代:对象存活率低,通常使用复制算法进行回收。新生代被进一步划分为Eden区、From区和To区,默认内存分配比为8:1:1。
  • 老年代:对象存活率高,通常使用标记-清除算法或标记-整理算法进行回收。

4. 垃圾收集器

垃圾收集器是执行垃圾回收操作的组件。在Java中,有多种不同类型的垃圾收集器,包括串行收集器、并行收集器、CMS收集器和G1收集器等。这些收集器采用不同的算法和策略来实现垃圾回收。

4.1 串行收集器(Serial GC)

串行收集器是最基本的垃圾收集器,使用单线程进行垃圾回收。它在进行垃圾收集时,必须暂停其他所有的工作线程,直到收集结束。因此,串行收集器适用于单CPU环境或内存较小的应用。

4.2 并行收集器(Parallel GC)

并行收集器使用多线程进行垃圾回收,提高了回收效率。它同样需要暂停其他工作线程,但回收过程是多线程的,因此适用于多CPU环境或吞吐量要求较高的应用。

4.3 CMS收集器(Concurrent Mark-Sweep GC)

CMS收集器是一种以获取最短回收停顿时间为目标的收集器。它使用并发标记和并发清除的方式来实现垃圾回收,大大减少了停顿时间。然而,CMS收集器在垃圾回收过程中会占用一部分CPU资源,并且可能产生内存碎片。

4.4 G1收集器(Garbage-First GC)

G1收集器是一种面向服务器的垃圾收集器,旨在满足大内存、多处理器的环境下对停顿时间的要求。它将堆内存划分为多个区域(Region),每次只收集一部分区域的垃圾。G1收集器采用并发标记和并发清除的方式,同时结合了复制算法和标记-整理算法的优点,实现了高吞吐量和低停顿时间。

5. 总结

Java JVM中的垃圾识别与分类是自动内存管理的重要组成部分。通过可达性分析算法,JVM能够准确识别出垃圾对象;通过不同的垃圾回收算法和收集器,JVM能够高效地回收这些垃圾对象所占用的内存空间。对于Java开发人员而言,深入理解JVM的垃圾回收机制有助于优化应用性能、解决内存泄漏等问题。


http://www.ppmy.cn/devtools/126733.html

相关文章

[k8s理论知识]3.docker基础(二)隔离技术

容器其实是一种沙盒技术,其核心是通过约束和修改进程的动态表现,为其创建一个边界。这个边界确保了应用与应用之间不会相互干扰,同时可以方便在不同的环境中迁移,这是PaaS最理想的状态。 程序是代码的可执行镜像,通常…

极简版Java敏感词检测SDK

敏感词工具 sensitive-word 基于 DFA 算法实现的高性能敏感词工具,开源在GitHub:https://github.com/houbb/sensitive-word。用于敏感词/违禁词/违法词/脏词等的识别和阻拦,是基于 DFA 算法实现的高性能 java 敏感词过滤工具框架。 使用场景…

滚雪球学Redis[5.3讲]:Redis持久化优化深度解析:RDB与AOF的策略选择与实践

全文目录: 🎉前言🚦Redis的监控与报警🔄1. 使用Redis自带工具进行监控🎯1.1 Redis常用监控命令🎯1.2 Redis配置文件中的监控相关参数 ⚙️2. 使用第三方工具进行Redis监控💡2.1 Prometheus与Red…

【Mac苹果电脑安装】DBeaverEE for Mac 数据库管理工具软件教程【保姆级教程】

Mac分享吧 文章目录 DBeaverEE 数据库管理工具 软件安装完成,打开效果图片Mac电脑 DBeaverEE 数据库管理工具 软件安装——v24.21️⃣:下载软件2️⃣:安装JDK,根据下图操作步骤提示完成安装3️⃣:安装DBeaverEE&#…

linux之rm使用技巧

对于包含乱码的文件或目录名,在Linux中删除它们可能会有些棘手,但还是可以通过一些方法来实现。下面是一些处理这种情况的方法: 方法1: 使用通配符 如果这些乱码文件或目录的名字有共同的特征(例如都是乱码)&#xf…

LeetCode 面试经典150题 151.反转字符串中的单词

题目: 给你一个字符串 s ,请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意:输入字符串 s中可能会…

Java中的异步编程:使用CompletableFuture提升并发性能

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 引言 在现代应用程序中,响应速度和并发性能变得越来越重要。随着处理任务变得复杂,应用程序常常需要同时处理多个任务,这对系统资源和性能提出了严峻的挑战。在传统的阻塞式编程模型中,线程等待任务完成往往…

Java笔试03

线性结构是指数据元素之间存在一对一的线性关系的数据结构。 树 不属于线性结构。树是由节点组成的层次结构,每个节点可以有多于两个的子节点。 队列 属于线性结构。队列是一种先进先出(FIFO)的数据结构,元素之间存在一对一的…