Java垃圾回收(GC)探析

Java 垃圾回收(GC)机制与算法详解 垃圾回收(Garbage Collection,GC)是 Java 自动内存管理的核心机制,负责。,避免内存泄漏和手动内存管理的复杂性。理解 GC 机制是 Java 性能优化的关键一步!整理阶段: 存活对象向一端移动。标记阶段: 标记所有可达对象。清除阶段: 回收未标记对象。存活对象复制到另一块。 阅读详情

Java 垃圾回收(Garbage Collection, GC)是 JVM 运行时内存管理的核心机制之一,用于自动回收不再使用的对象,避免内存泄漏并提高开发效率。

一、 GC算法的历史与演进

Java GC算法的发展是一个持续优化的过程,主要经历了以下几个阶段:

  • 早期(JDK 1.0 - 1.4): 这个阶段的GC相对简单,主要以串行(Serial)收集器为主,适用于内存较小、单核处理器的环境。
  • 并发与并行(JDK 5 - 8): 随着多核处理器的普及和应用规模的增大,对GC的停顿时间(Stop-The-World, STW)要求越来越高。CMS和G1等并发和并行收集器应运而生,显著降低了GC对应用的影响。
  • 低延迟与高吞吐(JDK 9+): 针对更大内存、更高并发的场景,以及对GC停顿时间极致追求的需求,ZGC和Shenandoah等更先进的收集器被引入,它们旨在实现毫秒级甚至亚毫秒级的GC停顿。

二、判断对象存活的方法

在垃圾回收器对堆内存回收前,需要判断对象是否存活。

  • 引用计数算法: 给每个对象添加一个引用计数器,每当对象被引用, 对象的引用计数器就加1,当引用失效时,引用计数器就减1。 直到引用计数器为0,就代表对象不再被引用。
  • 可达性算法: 通过GC ROOT的对象节点往下搜索,节点走过的路径被称为引用链。 如果一个对象不处于任何引用链,那么就可以判断此对象是不可达的。

三、什么是GC Root

GC Root(垃圾回收根)是 Java 垃圾回收(GC)算法中用于判断对象是否“存活”的起始点。

在这里插入图片描述

主要包括:

  • 栈中的引用(局部变量)
  • 静态变量
  • 常量引用
  • JNI 全局引用
  • 线程、ClassLoader 等特殊引用

GC Roots 可达性分析过程:

  1. 从 GC Roots 出发。
  2. 沿着对象引用关系搜索。
  3. 标记所有可达对象为存活。
  4. 未被标记的对象即为垃圾。

GC Roots 是一组 JVM 默认认为“永远存活”的对象引用,即使两个对象互相引用,但如果从 GC Roots 无法到达它们,它们依然会被回收。

四、常见的GC算法

引用计数 (Reference Counting)

一种历史悠久且直观的算法

引用计数是一种非常简单且直接的垃圾回收算法。它的核心思想是:

  • 为每个对象维护一个引用计数器。
  • 当有一个新的引用指向该对象时,计数器加 1。
  • 当一个引用失效(例如,引用被重新赋值为 null,或者引用离开了作用域)时,计数器减 1。
  • 当对象的引用计数器变为 0 时,说明没有其他对象再引用它,这个对象就可以被回收了。

优势:

  • 引用计数器归零时,对象可以立即被回收,无需等待完整的 GC 周期。这使得它的停顿时间非常短。
  • 更直观,容易理解。

劣势:

  • 致命问题就是处理不了循环引用,需要维护一个计数器。

标记-清除 (Mark-Sweep)

最基础的 GC 算法

在这里插入图片描述

其过程分为两个阶段:

  • 标记 (Mark):GC 会从一组被称为 GC Roots 的对象(如活跃线程的栈变量、静态变量等)开始,遍历所有可达(即被引用)的对象,并给它们打上“存活”的标记。
  • 清除 (Sweep):在标记阶段完成后,GC 会遍历整个堆内存。所有未被标记的对象都被认为是垃圾,其占用的内存将被回收。

优势:

  • 算法逻辑相对直观,易于实现。

劣势:

  • 碎片化严重,因为被回收的内存都是不连续的,尽管短时间回收了大部分空间,但如果突然需要分配一个大对象,而没有连续的空间可用,从而提前触发另一次 GC,甚至导致 OutOfMemoryError。
  • 标记和清除都需要遍历整个堆,如果堆内存很大,效率会比较低。

复制 (Copying) 算法

为了解决标记-清除算法的内存碎片问题,复制算法应运而生

在这里插入图片描述

它将可用内存划分为大小相等的两块,通常被称为 “From 空间” 和 “To 空间”。每次只使用其中一块内存。

  • 当 From 空间内存用完时,GC 会将所有存活的对象从 From 空间复制到 To 空间,并且这些对象在 To 空间中是紧凑排列的。
  • 复制完成后,From 空间的所有内存可以直接被清空。
  • 然后,From 空间和 To 空间的角色互换,下一次 GC 时使用新的 From 空间。

优势:

  • 不会产生连续的内存碎片,速度也很高效。

劣势:

  • 正如所描述的那样,需要划分两个相等的块,内存利用率直接减半,代价高昂。
  • 如果存活对象很多,复制的开销就会很大,更不适用于存活对象多的区域(老年代)

复制算法一般用于新生代。 因为新生代的GC非常频繁,每次GC的对象较多,存活的对象较少。 所以采用复制算法效率更高,复制时只需要复制少量存活的对象。

标记-整理 (Mark-Compact)

标记-整理算法是对标记-清除算法的一种改进。

在这里插入图片描述

它结合了标记-清除和复制算法的优点:

  • 标记 (Mark):与标记-清除算法相同,首先标记出所有可达对象。
  • 整理 (Compact):在标记完成后,GC 不会直接清除死亡对象,而是将所有存活的对象都向内存的一端移动,然后直接清理掉这一端边界以外的内存。

优势:

  • 通过移动存活对象,消除内存碎片。
  • 不像复制算法那样需要牺牲一半的内存空间。

劣势:

  • 所谓慢工出细活,标记-整理的效率是比标记-清除要低的,因为对象移动会涉及到内存拷贝和引用地址的更新。

标记-整理算法和标记-清除算法一样通常被用于 Java 的老年代,因为老年代的对象存活率较高,不适合使用复制算法。

分代收集 (Generational Collection)

分代收集算法并不是指某一种具体的垃圾收集算法, 而是将复制,标记-清除,标记-整理等算法合理运用到堆区的不同空间。 比如新生代使用复制算法,老年代使用标记清除或标记整理算法。

现代的几乎所有的JVM都使用分代收集,毕竟每种算法都有优缺点, 结合它们的特点,对不同的环境采用不同的算法是非常明智的选择。

分代收集基于两个重要的经验法则:

  • 弱代假设:绝大多数对象都是“朝生夕灭”的,在新生代中很快就会死亡。
  • 强代假设:熬过越多次垃圾收集过程的对象就越难以死亡,它们倾向于长时间存活。

根据这两个假设,堆内存通常被划分为:

  • 新生代 (Young Generation):
    • 主要存放新创建的对象。
    • 根据弱代假设,这里对象的死亡率非常高。
    • 通常采用复制算法进行垃圾回收(称为 Minor GC),因为复制少数存活对象比清除大量死亡对象更高效。
    • 新生代又被细分为一个 Eden 区和两个 Survivor 区 (From Space 和 To Space)。
  • 老年代 (Old Generation):
    • 存放经过多次 Minor GC 仍然存活的对象(即长期存活的对象)。
    • 根据强代假设,这里对象的死亡率较低。
    • 通常采用标记-整理算法或标记-清除-整理结合的算法进行垃圾回收(称为 Major GC 或 Full GC),以避免内存碎片,并适应高存活率的特点。

优势:

通过对不同代的特点使用不同的 GC 算法,大大优化了整体的垃圾回收性能。

五、一次GC的过程

对象优先在eden区被分配,当eden区内存不足时, JVM发起Minor GC。Minor GC的范围包括eden和From Survivor:

首先JVM会根据可达性算法标记出所有存活的对象。

如果存活的对象中,有的对象的年龄已经达到晋升阈值 (阈值是动态计算的,可以通过-XX:MaxTenuringThreshold设置最大年龄阈值), 那么将已经达到阈值的对象复制到老年代中。

如果To Survivor空间不足以存放剩余存活对象, 则直接将存活的对象提前复制到老年代。 如果老年代也没有足够的空间存放存活的对象, 那么将触发Full GC(GC整个堆,包括新生代和老年代)。

如果To Survivor可以存放存活的对象, 那么将对象复制到To Survivor空间,并清理eden和From Survivor。

此时From Survivor为空, 那么From Survivor就成为了下一次的To Survivor, 此时To Survivor存放着存活的对象,就成为了下一次的From Survivor。 这样From Survivor与To Survivor就是不断交替复制的使用。

老年代的空间比新生代的空间要大, 所以老年代的Major GC要比Minor GC耗时更长。 根据垃圾回收器的不同,老年代的GC算法也不同。

六、动态年龄阈值

动态年龄阈值是 JVM 为了防止 Survivor 区溢出,根据对象年龄分布动态调整晋升年龄的智能机制 —— 不一定等到年龄 15,只要“某批对象快占满 Survivor”,就提前晋升。

JVM并不要求对象年龄一定要达到 MaxTenuringThreshold 才会 晋升到老年代,晋升的年龄阈值是动态计算的。 如果在Survivor中,某个相同年龄阶段的所有对象大小的总和 大于Survivor区域的一半,则大于等于这个年龄的所有对象 可以直接进入老年代,无需等到MaxTenuringThreshold。

七、最后

算法名称关键步骤核心特点典型应用场景
标记-清除1. 从GC Roots遍历标记存活对象 2. 直接回收未标记区域产生内存碎片早期JVM老年代
复制算法1. 将存活对象从From区复制到To区 2. 清空整个From区需要双倍内存空间新生代(Survivor区)
标记-整理1. 标记存活对象 2. 将所有存活对象向内存一端移动 3. 清理边界外空间移动对象开销大,无碎片老年代
分代收集- 新生代:复制算法 - 老年代:标记-清除/标记-整理针对不同生命周期对象优化现代JVM默认方案

关键对比维度:

  1. 内存效率:复制算法 > 标记-整理 > 标记-清除
  2. 空间利用率:标记-整理(100%)> 标记-清除(有碎片)> 复制算法(50%)
  3. 时间复杂度:标记-清除 ≈ 复制算法 < 标记-整理(需对象移动)
Java 垃圾回收(GC) Java 的垃圾回收(GC)是 Java 虚拟机(JVM)对内存管理的核心机制之一。GC 的作用是 自动回收不再被使用的对象,从而释放堆内存,避免程序因手动管理内存出现问题(如内存泄漏、悬挂指针等)。 阅读详情

相关推荐

Java GC垃圾回收机制

文章目录一、Java GC二、GC 回收的对象三、GC 回收过程1、图解分代内存1.1 年轻代1.2 年老代1.3 永久代2、图解 GC 回收过程对象分配策略3、Minor GC 和 Full GC 本文内容基于目前使用最广泛的 HotSpot JVM。 参考书籍:《深入理解Java虚拟机:JVM高级特性与最佳实践》–周志明 一、Java GC Java 垃圾回收机制是由 GC(Garbage...

媛测 696

JVM学习笔记Ⅸ

垃圾回收器:七种经典的垃圾回收器,及其对比

MeiMing_104的博客 936

Java 垃圾回收(GC)

前言==垃圾回收(Garbage Collection,简写为 GC)可能是虚拟机众多知识点中最为大众所熟知的一个了,也是Java开发者最关注的一块知识点。Java 语言开发者比 C 语言开发者幸福的地方就在于,我们不需要手动释放对象的内存,JVM 中的垃圾回收器(Garbage Collector)会为我们自动回收。但是这种幸福是有代价的:一旦这种自动化机制出错,我们又不得不去深入理解 GC 回收机制,甚至需要对这些"自动化"的技术实施必要的监控和调节。

2501_90389279的博客 1026

Java中的垃圾回收(GC)

垃圾回收,英文名Garbage Collection(GC). Java进程在启动后,会创建垃圾回收线程,来对内存中无用的对象进行回收. 目录 1. 那么问题来了,什么是垃圾? 2. 什么是垃圾回收? 3. 什么时候回收垃圾? 4. 判断是否为垃圾的算法 4.1 引用计数法 4.2 可达性分析算法 5. 回收的区域 5.1 方法区的gc 5.2 堆的gc 6. 垃圾回收算法 6.1 标记清除算法(老年代的回收算法) 6.2 复制算法(新生代的回收算法) 6.3 标记整理算法.

weixin_43939602的博客 2438

Java8的GC垃圾回收(一)

Java垃圾回收概况   Java GC(Garbage Collection,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制。概括地说,该机制对JVM中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,...

wolfcode_cn的博客 6058

JAVA垃圾回收(GC)算法

GC算法前言GC算法二、使用步骤1.引入库2.读入数据总结 前言 什么是GC: GC:Garbage Collection(垃圾回收)找到内存空间的垃圾,回收垃圾。 GC算法 二、使用步骤 1.引入库 代码如下(示例): import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.filterwarnings('ignore') im

dycy的博客 1697

JVM中的GC垃圾回收

文章目录JVM中的GC垃圾回收什么是GC,为什么需要GC早期的垃圾回收行为Java自动内存管理介绍垃圾回收的相关算法标记阶段:引用计数算法引用计数算法的原理引用计数算法的优缺点标记阶段:可达性分析算法GC Roots清除阶段:标记-清除算法清除阶段:复制算法清除阶段:标记-压缩(或标记-整理,Mark-Compact)算法 JVM中的GC垃圾回收 什么是GC,为什么需要GC 什么是垃圾? 垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。 为什么需要GC? 如果不及时的对垃圾进行清理

xzy的博客 1713

Java GC(垃圾回收)机制知识总结

Java GC系列本部分来自Java GC系列(1):Java垃圾回收简介Java的内存分配与回收全部由JVM垃圾回收进程自动完成。与C语言不同,Java开发者不需要自己编写代码实现垃圾回收。这是Java深受大家欢迎的众多特性之一,能够帮助程序员更好地编写Java程序。下面四篇教程是了解Java 垃圾回收(GC)的基础: 垃圾回收简介 圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 这篇教

MapleStory的博客 1422

GC垃圾回收

垃圾回收概念、垃圾回收算法、垃圾回收相关概念、几种引用类型

scj1022的博客 1381

湿敏电阻HR202的两种驱动方案实测:IO充放电法 vs. 交流方波ADC法,哪个更适合你?

本文深入评测湿敏电阻HR202的两种驱动方案:IO充放电法和交流方波ADC法。通过原理图分析、精度实测和资源占用对比,揭示交流方波ADC法在精度和稳定性上的优势,特别适合长期监测场景。同时提供IO充放电法在资源受限情况下的应用建议,帮助工程师根据项目需求做出最优选择。

weixin_30421809的博客 466

四阶龙格库塔法求解一次常微分方程组(python实现)

之前在博客发布了关于使用四阶龙格库塔方法求解一次常微分方程组的文章,由于代码缺少具体的验证,部分朋友可能存在疑问,因此这里打算再重新写一篇博客来验证一下程序的正确性,另外,这里是使用python语言来实现的。

HelloWorldTM的博客 8542

java面试-GC垃圾回收机制

从空间的角度讲,标记清除后会产生大量不连续的内存碎片, 内存碎片太多可能会导致以后程序运行过程中在需要分配较大对象时,无法找到足够的连续内存而不得不提前触发一次垃圾收集动作。这种算法没什么特别的,无非是上面内容的结合罢了,根据对象的生命周期的不同将内存划分为几块,然后根据各块的特点采用最适当的收集算法。:在新生代中,每次GC时都发现有大批对象死去,只有少量存活(新生代中98%的对象都是“朝生夕死”),那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成GC。清除阶段:统一回收所有被标记的对象。

qq_41024101的博客 3877

Plant Simulation新手入门:从零开始搭建工厂布局仿真模型(附完整代码)

本文为Plant Simulation新手提供了一个从零开始搭建工厂布局仿真模型的完整实战教程。通过一个玩具工厂车间布局优化的具体案例,详细讲解了从数据准备、模型构建、核心逻辑编程到连接遗传算法进行自动优化的全流程,并附有完整代码示例,帮助读者快速掌握这一工业仿真软件的核心应用。

metal的博客 553

Java进阶—GC回收(垃圾回收)

垃圾回收(Garbage Collection,GC)是Java虚拟机(JVM)的一项重要功能,用于自动管理程序中不再使用的内存。在Java中,程序员不需要手动释放内存,因为GC会自动检测并回收不再使用的对象,从而减少内存泄漏的风险。

tanmoney的博客 2124

Unity类银河战士恶魔城学习总结(P103之前 Enemy相关 , 骷髅战士,状态机,敌人状态,)

udemy的Alex银河战士恶魔城,记录我自己的学习,代码会逐渐每一p更新,仅供参考学习。

suzh1qian的博客 1631

TurboQuant: Online Vector Quantization with Near-optimal Distortion Rate

这篇被 ICLR 2026 接收的论文提出了一种名为TurboQuant的全新在线向量量化(Vector Quantization, VQ)算法。该研究的核心目标是解决大语言模型(LLM)在长上下文推理时面临的 KV Cache 显存消耗瓶颈,以及大规模向量数据库在近似最近邻检索中的存储与延迟问题。有别于现有技术,TurboQuant 是一种无需任何校准数据、无需训练的在线算法(Data-oblivious)。

c_cpp_csharp的专栏 118

面试干货2——你对Java GC垃圾回收有了解吗?

GC垃圾回收1. 什么是GC2. GC主要针对区域3. Java如何判断对象是否存活4. GC垃圾回收机制4.1 标记-清除法4.2 标记-整理法4.3 复制算法4.4 分代收集算法5. 内存分配策略及垃圾回收过程5.1 为什么新生代要有survivor区?5.2 为什么要有两个survivor区?6. 总结 1. 什么是GC         GC全名Garbage Collection,垃圾收集,垃圾回收,这是Java区别于C

qq_41563912的博客 3159

真随机数与伪随机数

前面我们学习了LFSR,这个玩意落地到具体的应用是什么呢?没错是寄存器,这里在网络找到了几个回答,这里做个记录,下面一起来学习一下吧。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 1062

Java 垃圾回收

一般来说,Java开发人员大多关注业务逻辑的实现,但是,充分理解Java的 JVM中堆内存的分配和垃圾处理收集 这些内容可以让我们更有效地利用资源,更深刻的理解自己所写的代码。

码刀攻城 1412

C#与天文观测:Celestia模拟星空的奇幻之旅

Celestia就像一艘穿梭在星海中的小飞船,带领我们遨游宇宙。C#则是这艘飞船的智能导航系统,用代码指挥它飞向任何我们向往的星球或星系。首先,下载并安装Celestia,熟悉其基本操作和功能。创建一个星空目标列表,包括不同的恒星、行星和星系。// 示例:定义观察目标列表new SpaceObject("太阳"),new SpaceObject("月球"),new SpaceObject("火星")

java专栏 1456

YOLOv11改进策略【模型轻量化】| 替换华为的极简主义骨干网络:VanillaNet

本文记录的是基于VanillaNet的YOLOv11轻量化改进方法研究。VanillaNet的极简主义在于无 shortcut 连接,并且在网络的每个阶段仅使用一层卷积,无额外复杂模块,仅通过自身简洁的架构设计和训练策略,实现有效地训练和优化。本文在替换骨干网络中配置了原论文中的、和11种模型,以满足不同的需求。

Limiiiing的博客 1723

GC 垃圾回收

垃圾回收机制是由垃圾收集器Garbage Collection GC来实现的,GC是后台的守护进程。它的特别之处是它是一个低优先级进程,但是可以根据内存的使用情况动态的调整他的优先级。因此,它是在内存中低到一定限度时才会自动运行,从而实现对内存的回收。这也是垃圾回收的时间不确定的原因 为何要这样设计:因为GC也是进程,也要消耗CPU等资源,如果GC执行过于频繁会对java的程序的执行产生较大的影响(java解释器本来就不快),因此JVM的设计者们选着了不定期的gc。 一、为什么要进行垃圾回收 我们知道J.

栗筝i的博客 3585

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

垃圾回收GC

垃圾回收(Garbage Collection, GC)是一种自动管理内存的机制,主要用于回收不再使用的对象,防止内存泄漏,并提高程序的稳定性和可维护性。在程序运行过程中,会不断地分配内存来存储各种数据,当这些数据不再被程序使用时,其所占用的内存就变成了“垃圾”。如果不及时回收这些内存,会导致内存泄漏,最终使程序耗尽系统资源而崩溃。垃圾回收机制的主要目的就是自动检测并回收这些不再使用的内存,让开发者无需手动管理内存的分配和释放,从而降低了编程的复杂度,提高了程序的稳定性和可维护性。GC 由运行时系统。

ydl1128的博客 1235

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

垃圾回收,几种GC算法及GC机制

常见垃圾回收算法、GC算法、GC机制

qq_73181349的博客 1361

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java 垃圾回收机制 GC 及常用的垃圾回收算法

在 Java 中,所有的对象都是要存在内存中的(也可以说内存中存储的是一个个对象),因此我们将内存回收,也可以叫做死亡对象的回收;;而栈中的局部变量会跟随栈帧的声明周期结束,静态变量生命周期是整个程序,因此都不需要 GC 回收;GC 回收操作可分为两步——找到垃圾对象和回收垃圾对象。

2201_75456895的博客 1183

Java 垃圾回收(GC)浅析

本文全面解析了 Java 垃圾回收(GC)机制,涵盖其定义、必要性、工作原理及常见算法,如标记-清除、复制和分代收集。详细介绍了多种 GC 收集器及其适用场景,并探讨了如何通过 GC 日志和监控工具优化性能。此外,本文还列举了内存泄漏检测与预防的方法,以及相关的知识点,如弱引用和 JIT 编译器优化,帮助读者理解并有效管理 Java 应用的内存使用,提升程序性能。

进一步有进一步的欢喜~ 1024
上一篇: Java-JVM探析
下一篇: HashMap 底层原理 (JDK 1.8 源码分析)
_蓝橙
博客等级 码龄7年 1179粉丝 174原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值