垃圾回收的核心知识点解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 垃圾回收的核心知识点解析

Java运行时内存中的程序计数器、虚拟机栈、本地方法栈这三部分区域其生命周期与相关线程有关,随线程而生,随线程而灭。而程序计数器就是一个单纯存地址的整数也不需要关心,因此我们GC(垃圾回收)的主要目标就是堆(堆中存放着几乎所有实例对象)!

检测垃圾

一个对象,如果后续不再被使用且没有引用指向它,就可以认为是垃圾。

有以下方法可知对象是否有引用指向:

引用计数算法

在主流的JVM中没有选用引用计数法来管理内存,最主要的原因就是引用计数法无法解决对象的循环引用问题 Python,PHP采取了引用计数算法。

给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即可被回收。

Test test1 = new Test();
        Test test2 = test1;
        Test test3 = test1;
        Test test4 = test1;

此算法存在两个缺陷:

  1. 浪费内存空间
  2. 存在循环引用的情况
    用一个例子来解释一下循环引用的问题:
class Test {
 public Test test;
}
        Test test1 = new Test();
        Test test2 = new Test();
        test1.test=test2;
        test2.test=test1;

此时test1与test2 销毁了,两个对象的引用计数分别减一。

此时这两个对象的引用计数不为0,不能作为垃圾且无法使用,陷入了一个逻辑上的循环。

可达性分析算法

通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为"引用链",当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的

在java中,可作为GC Roots(垃圾回收根对象)的对象有以下几种:

  1. 栈上的局部变量
  2. 常量池中引用的对象
  3. 方法区中类静态属性引用的对象

只有从GC Roots对象开始,通过引用链可达的对象才被认为是存活的,而无法通过引用链访问的对象则会被判定为垃圾,并进行回收。

缺点:

  1. 遍历开销:可达性分析算法需要遍历整个对象图以确定每个对象的可达性。对于大型堆和复杂的引用关系,遍历开销可能非常大,特别是在全局垃圾回收中。这可能会导致垃圾回收的性能下降。
  2. 延迟回收:可达性分析算法需要遍历整个对象图,从GC Roots开始,逐个检查每个对象的引用关系。这个过程可能需要消耗大量的时间,且在垃圾回收期间,应用程序的执行会被暂停(STW - Stop-The-World)。因此,可达性分析算法可能导致较高的延迟,影响程序的响应性能。

回收垃圾

标记清除算法

算法分为"标记"和"清除"两个阶段 : 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

回收前:

回收后:

不足:

  1. 标记和清除这两个过程的效率都不高。
  2. 标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。

复制算法

"复制"算法是为了解决"标记-清理"的效率问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。

简单来说复制算法就是把不是垃圾的对象拷贝到未使用的那一边,然后再统一释放刚才使用过的那一块区域

缺点:

  1. 内存利用率比较低。
  2. 如果当前区域的大部分对象都需要保留垃圾很少,那么此时的复制成本就比较高。

标记整理算法

标记整理算法的基本流程:

  1. 标记:从根对象开始,通过可达性分析算法,标记所有从根对象可达的存活对象。标记过程中,通常使用标记位(标记状态)来标记对象是否为存活对象。
  2. 整理:将所有存活对象移到堆的一端,紧凑排列,以便释放出连续的一段内存空间。在移动存活对象时,需要更新对这些对象的引用,确保引用指向移动后的新位置。
  3. 更新引用:在堆中,遍历所有存活对象的引用,将其指向新的位置。这是为了避免悬挂指针(引用指向被移动或已回收的对象)的问题。
  4. 释放未标记的对象:在整理后的堆中,所有没有被标记的对象都可以被认为是垃圾对象,可以直接被回收。

优点:解决了内存碎片问题。

缺点:搬运复制开销比较大。

分代算法

分代算法主要基于一种观察:大部分对象的生命周期都比较短暂。根据这个观察,分代算法将堆内存划分为不同的代(Generation),每一代中对象的生命周期不同,并且根据对象的生命周期将不同的垃圾回收策略应用于不同的代中。

一般来说,分代堆内存被划分为年轻代(Young Generation)和老年代(Old Generation)两个主要部分

年轻代

年轻代是存放新创建的对象的地方,大部分对象在创建后很快就变为垃圾对象。年轻代通常进一步分为Eden区和两个Survivor区。新创建的对象首先放入Eden区,当Eden区满时,不会被回收的对象会被转移到一个Survivor区。当一个Survivor区满时,其中的存活对象会被复制到另一个Survivor区或者老年代。经过多次垃圾回收后依然存活的对象将晋升到老年代。

年轻代通常采用复制算法(Copying)作为垃圾回收策略,因为新创建的对象的生命周期短暂,复制算法可以更好地利用对象的特点。

老年代

老年代是存放存活时间较长的对象的地方,老年代的对象生命周期较长,垃圾回收频率相对较低。对于老年代的垃圾回收,可以采用标记-清除(Mark-Sweep)或者标记-整理(Mark-Compact)等算法。

分代算法通过区分不同代的对象,针对不同代采取不同的垃圾回收策略,可以提高垃圾回收效率和系统性能。年轻代的频繁垃圾回收可以快速回收新创建对象,老年代的较少回收可以减少全局垃圾回收的引发,提高应用程序的响应性。这种分代垃圾回收策略在大多数的垃圾收集器中都有应用。


相关文章
|
24天前
|
监控 算法 Java
Java虚拟机(JVM)的垃圾回收机制深度解析####
本文深入探讨了Java虚拟机(JVM)的垃圾回收机制,旨在揭示其背后的工作原理与优化策略。我们将从垃圾回收的基本概念入手,逐步剖析标记-清除、复制算法、标记-整理等主流垃圾回收算法的原理与实现细节。通过对比不同算法的优缺点及适用场景,为开发者提供优化Java应用性能与内存管理的实践指南。 ####
|
2月前
|
存储 前端开发 JavaScript
JavaScript垃圾回收机制深度解析
【10月更文挑战第21】JavaScript垃圾回收机制深度解析
112 59
|
15天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
5月前
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
76 0
|
2月前
|
数据安全/隐私保护 流计算 开发者
python知识点100篇系列(18)-解析m3u8文件的下载视频
【10月更文挑战第6天】m3u8是苹果公司推出的一种视频播放标准,采用UTF-8编码,主要用于记录视频的网络地址。HLS(Http Live Streaming)是苹果公司提出的一种基于HTTP的流媒体传输协议,通过m3u8索引文件按序访问ts文件,实现音视频播放。本文介绍了如何通过浏览器找到m3u8文件,解析m3u8文件获取ts文件地址,下载ts文件并解密(如有必要),最后使用ffmpeg合并ts文件为mp4文件。
|
2月前
|
存储 监控 算法
Java中的内存管理与垃圾回收机制解析
本文深入探讨了Java编程语言中的内存管理方式,特别是垃圾回收机制。我们将了解Java的自动内存管理是如何工作的,它如何帮助开发者避免常见的内存泄漏问题。通过分析不同垃圾回收算法(如标记-清除、复制和标记-整理)以及JVM如何选择合适的垃圾回收策略,本文旨在帮助Java开发者更好地理解和优化应用程序的性能。
|
3月前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
124 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
3月前
|
监控 算法 Java
深入解析Java中的垃圾回收机制
本文旨在全面解析Java的垃圾回收机制,探讨其工作原理、常见算法以及在实际开发中的应用。通过对这一重要主题的深入分析,希望帮助读者更好地理解Java虚拟机(JVM)如何管理内存,从而编写出更高效、稳定的Java应用程序。
|
2月前
|
监控 算法 Java
Java中的垃圾回收机制深度解析
【10月更文挑战第10天】 本文深入探讨了Java语言核心特性之一的垃圾回收机制(Garbage Collection, GC),揭示了其在内存管理中的关键角色。通过对GC的工作原理、分类、算法以及调优策略的细致分析,旨在帮助开发者更好地理解并有效利用这一机制,提升Java应用的性能与可靠性。不同于常规摘要,本文聚焦于为读者提供一份关于Java GC全面而深入的解读,助力把握Java内存管理的精髓。
|
3月前
|
存储 监控 算法
Java中的内存管理与垃圾回收机制解析
本文深入探讨了Java编程语言中的内存管理策略和垃圾回收机制。首先介绍了Java内存模型的基本概念,包括堆、栈以及方法区的划分和各自的功能。进一步详细阐述了垃圾回收的基本原理、常见算法(如标记-清除、复制、标记-整理等),以及如何通过JVM参数调优垃圾回收器的性能。此外,还讨论了Java 9引入的接口变化对垃圾回收的影响,以及如何通过Shenandoah等现代垃圾回收器提升应用性能。最后,提供了一些编写高效Java代码的实践建议,帮助开发者更好地理解和管理Java应用的内存使用。
44 3

推荐镜像

更多