当前位置: 首页 > news >正文

深入理解JVM的垃圾收集(GC)机制

引言

首先我们来介绍垃圾收集的概念,什么是垃圾收集?

        垃圾收集 (Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存爆掉。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

垃圾收集需要完成的三件事情

        哪些是垃圾?

        怎么样回收?

        什么时间回收?

        既然JVM要进行垃圾收集,首先就要判定哪些是垃圾?


 1. 哪些是垃圾

        我们要判定哪些对象还“存活”着,哪些已经“死去”,有两种算法:引用计数法可达性分析

1.1 脑门刻字法- 引用计数法

 思路

        在对象中添加一个引用计数器,通过计数器的加一减一操作,引用就加一,失效就减一。为零就回收。

        引用计数算法看似很美好,但实际上它存在一个很大的问题,那就是无法解决循环依赖的问题。

public static void testGC() {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
// 假设在这行发生GC,objA和objB是否能被回收?
System.gc();
}

        如果a和b相互引用,然后将这两个对象的引用设置为 null,理论上它们会在接下来被垃圾回收器回收。但由于它们相互引用着对方,导致它们的引用计数永远都不会为 0,通过引用计数算法,也就永远无法通知 GC 收集器回收它们。

1.2 平地长树法-可达性分析

思路:     

        大白话就是:只要与GC Roots根对象关联上,就不回收。

        正式的话就是:通过 GC Roots 作为起点,然后向下搜索,搜索走过的路径被称为 Reference Chain(引用链),当一个对象到 GC Roots 之间没有任何引用相连时,即从 GC Roots 到该对象节点不可达,则证明该对象是需要垃圾收集的。

        所谓的 GC Roots,就是一组必须活跃的引用,不是对象,它们是程序运行时的起点,是一切引用链的源头。在 Java 中,GC Roots 包括以下几种:

  • 虚拟机栈中的引用(方法的参数、局部变量等)
  • 本地方法栈中 JNI (Java Native Interface)的引用
  • 类静态变量
  • 运行时常量池中的常量(String 或 Class 类型)

2. 怎么样回收

2.1 分代假说

分代收集理论

        比如:有一堆2分钟就要被清理的和一堆两个小时的被清理的。分成两堆

        强分代假说:活得越久的,就越倾向于活下去 老年代 占2

        弱分代假说:大部分朝生夕灭。 新生代 占1

        跨代引用假说: 仅占极少数 (死的贼快的早死了,死的慢的就直接老年代了。)   

                实现:在新生代建立一个全局的数据结构,这个结构把老年代划分成若干个小块,标识出老年代的哪一块内存会存在跨代引用。包含了跨代引用小块内存的对象会被加入GCRoots。

2.2 收集算法

1》标记清除

        标记出要被回收的对象,标记完成后回收这些标记的对象。或者标记出存活的对象,回收未被标记的。

        优势:实现简单

        劣势:①产生空间碎片问题

                  ②stop the world(在打标记的过程中,不能有新的对象产生。或者新的对象不打标记)

解决空间碎片化:

        标记复制

2》标记复制

        把内存划分为容量相同的两块,每次只使用其中的一块。当这一块内存满了,就将还存活的对象复制到另外一块上,把原来满的那块内存清理掉。

        好处:没有空间碎片,实现简单高效

        坏处:收集效率不高的时候,使用这个算法不合适

                   仅适用于收集效率高,朝生夕死合适

                   只有一半的有效空间,另一半只能等着

        优化:把整个新生代划分成三部分

3》标记整理

        适用于老年代。标记出要被回收的对象或者存活的对象,将所有存活的对象都向内存空间一端移动,然后清理掉边界以外的内存。

        好处:整理完后,没有空间碎片

        坏处:需要移动对象


Stop The  World

        "Stop The World"是 Java 垃圾收集中的一个重要概念。在垃圾收集过程中,JVM 会暂停所有的用户线程,这种暂停被称为"Stop The World"事件。

        这么做的主要原因是为了防止在垃圾收集过程中,用户线程修改了堆中的对象,导致垃圾收集器无法准确地收集垃圾。

        值得注意的是,"Stop The World"事件会对 Java 应用的性能产生影响。如果停顿时间过长,就会导致应用的响应时间变长,对于对实时性要求较高的应用,如交易系统、游戏服务器等,这种情况是不能接受的。

        因此,在选择和调优垃圾收集器时,需要考虑其停顿时间。Java 中的一些垃圾收集器,如 G1 和 ZGC,都会尽可能地减少了"Stop The World"的时间,通过并发的垃圾收集,提高应用的响应性能。

        总的来说,"Stop The World"是 Java 垃圾收集中必须面对的一个挑战,其目标是在保证内存的有效利用和应用的响应性能之间找到一个平衡。

http://www.dtcms.com/a/275003.html

相关文章:

  • Next知识框架、SSR、SSG和ISR知识框架梳理
  • c++——运算符的重载
  • 鸿蒙开发之ArkTS常量与变量的命名规则
  • 面向对象编程
  • [面试] 手写题-选择排序
  • 持有对象-泛型和类型安全的容器
  • 深度学习中的归一化技术详解:BN、LN、IN、GN
  • Kubernetes 高级调度特性
  • C语言:位运算
  • Redis 哨兵机制
  • 多代理系统(multi-agent)框架深度解析:架构、特性与未来
  • 无代码自动化测试工具
  • STM32G473串口通信-USART/UART配置和清除串口寄存器状态的注意事项
  • 隆重介绍 Xget for Chrome:您的终极下载加速器
  • 开源界迎来重磅核弹!月之暗面开源了自家最新模型 K2
  • 从延迟测试误区谈起:SmartPlayer为何更注重真实可控的低延迟?
  • gitee 代码仓库面试实际操作题
  • Cadence Virtuoso中如何集成Calibre
  • Java进阶---并发编程
  • 打造未来制造核心力:虚拟调试的价值与落地思路
  • YOLO-DETR如何提升小目标的检测效果
  • 【数据结构与算法】数据结构初阶:详解顺序表和链表(三)——单链表(上)
  • OpenCV实现感知哈希(Perceptual Hash)算法的类cv::img_hash::PHash
  • 商城网站建设实务
  • Ragflow-plus本地部署和智能问答及报告编写应用测试
  • 标准化模型格式ONNX介绍:打通AI模型从训练到部署的环节
  • C语言易错点(二)
  • C++包管理工具:conan2常用命令详解
  • JVM-----【并发可达性分析】
  • Android 12系统源码_分屏模式(一)从最近任务触发分屏模式