news 2026/10/23 2:08:57

JVM垃圾回收基础:对象存活判定与垃圾标记算法(附代码演示)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JVM垃圾回收基础:对象存活判定与垃圾标记算法(附代码演示)

在JVM的垃圾回收机制中,对象存活判定和垃圾标记算法是非常重要的基础内容。准确地判定对象是否存活,以及选择合适的垃圾标记算法,对于高效地进行垃圾回收至关重要。接下来,我们将深入探讨对象存活判定的方法以及常见的垃圾标记算法,并通过Java代码进行演示。

目录

      • 对象存活判定的方法
        • 引用计数法
        • 可达性分析算法
      • 标记算法
        • 标记 - 清除算法
        • 标记 - 整理算法
      • 总结

对象存活判定的方法

引用计数法

引用计数法是一种比较简单的对象存活判定方法。它的核心思想是,给每个对象添加一个引用计数器,每当有一个地方引用该对象时,计数器的值就加1;当引用失效时,计数器的值就减1。当计数器的值为0时,就认为该对象不再被使用,是一个垃圾对象,可以被回收。

用大白话来说,就好比一个物品,每有一个人使用它,它的“使用人数”就加1,当没有人再使用它时,“使用人数”为0,这个物品就可以被扔掉了。

不过,引用计数法存在一个明显的问题,就是无法解决循环引用的问题。例如,对象A引用了对象B,对象B又引用了对象A,此时它们的引用计数器都不为0,但实际上它们可能已经没有其他外部引用,应该被回收。

以下是一个简单的Java代码示例,展示引用计数法的基本原理:

classMyObject{MyObjectreference;}publicclassReferenceCountingExample{publicstaticvoidmain(String[]args){MyObjectobjA=newMyObject();MyObjectobjB=newMyObject();// 相互引用objA.reference=objB;objB.reference=objA;// 此时objA和objB的引用计数器都不为0,但它们已经没有其他外部引用}}
可达性分析算法

可达性分析算法是目前主流的对象存活判定方法。它的基本思路是,从一系列被称为“GC Roots”的对象开始,通过引用关系向下搜索,能够被搜索到的对象就是存活对象,而那些无法被搜索到的对象则被判定为垃圾对象,可以被回收。

通俗来讲,就像从一个树根开始,沿着树枝去寻找树叶,如果一片树叶和树根之间有树枝相连,那么这片树叶就是“存活”的,否则就是“死亡”的,可以被摘掉。

常见的GC Roots对象包括:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象。例如,在一个方法中创建的对象,如果该方法还没有执行完,那么这个对象就被虚拟机栈中的本地变量引用,是存活对象。
  • 方法区中类静态属性引用的对象。比如,一个类的静态成员变量引用的对象,只要这个类还存在于方法区,该对象就是存活的。
  • 方法区中常量引用的对象。例如,使用final关键字定义的常量所引用的对象。
  • 本地方法栈中JNI(Java Native Interface)引用的对象。

以下是一个简单的Java代码示例,展示可达性分析算法的基本原理:

publicclassReachabilityAnalysisExample{publicstaticvoidmain(String[]args){// 创建一个对象Objectobj=newObject();// obj是一个GC Roots可达的对象,所以是存活对象// 让obj不再引用该对象obj=null;// 此时该对象无法从GC Roots到达,可能会被垃圾回收}}

标记算法

标记 - 清除算法

标记 - 清除算法是一种基本的垃圾标记算法,它分为两个阶段:标记阶段和清除阶段。在标记阶段,从GC Roots开始遍历,标记所有存活的对象;在清除阶段,将那些没有被标记的对象(即垃圾对象)进行清除。

用大白话解释,就好比在一片森林里,先把那些还“活着”的树做上标记,然后把没有标记的树砍掉。

不过,标记 - 清除算法存在一些缺点。首先,它会产生大量的内存碎片,就像砍树后留下了很多小块的空地,可能导致后续无法分配较大的连续内存空间。其次,标记和清除的效率都不高,尤其是在对象数量较多的情况下。

以下是一个简单的Java代码示例,模拟标记 - 清除算法的执行过程:

importjava.util.ArrayList;importjava.util.List;classMyObject{intid;publicMyObject(intid){this.id=id;}}publicclassMarkAndSweepExample{publicstaticvoidmain(String[]args){List<MyObject>objects=newArrayList<>();// 创建一些对象for(inti=0;i<10;i++){objects.add(newMyObject(i));}// 模拟标记阶段List<MyObject>markedObjects=newArrayList<>();for(MyObjectobj:objects){if(obj.id%2==0){markedObjects.add(obj);}}// 模拟清除阶段objects.removeIf(obj->!markedObjects.contains(obj));// 输出存活的对象for(MyObjectobj:objects){System.out.println("存活对象的ID: "+obj.id);}}}
标记 - 整理算法

标记 - 整理算法也是先进行标记阶段,从GC Roots开始遍历,标记所有存活的对象。然后,在整理阶段,将所有存活的对象向内存的一端移动,然后直接清理掉边界以外的内存空间。

这就好比在一个房间里,先把有用的物品标记出来,然后把这些有用的物品都挪到房间的一边,最后把另一边的空间清理干净。

标记 - 整理算法解决了标记 - 清除算法产生内存碎片的问题,因为它会对存活对象进行整理,使得内存空间更加连续。但它的缺点是整理过程需要移动对象,会带来一定的性能开销。

以下是一个简单的Java代码示例,模拟标记 - 整理算法的执行过程:

importjava.util.ArrayList;importjava.util.List;classMyObject{intid;publicMyObject(intid){this.id=id;}}publicclassMarkAndCompactExample{publicstaticvoidmain(String[]args){List<MyObject>objects=newArrayList<>();// 创建一些对象for(inti=0;i<10;i++){objects.add(newMyObject(i));}// 模拟标记阶段List<MyObject>markedObjects=newArrayList<>();for(MyObjectobj:objects){if(obj.id%2==0){markedObjects.add(obj);}}// 模拟整理阶段objects.clear();objects.addAll(markedObjects);// 输出存活的对象for(MyObjectobj:objects){System.out.println("存活对象的ID: "+obj.id);}}}

总结

通过学习对象存活判定的方法和常见的垃圾标记算法,我们能够更好地理解JVM的垃圾回收机制。引用计数法简单但存在循环引用问题,可达性分析算法是主流的对象存活判定方法。标记 - 清除算法会产生内存碎片,标记 - 整理算法则解决了这个问题,但会带来一定的性能开销。在实际应用中,我们需要根据具体的场景和需求,选择合适的垃圾标记算法进行垃圾回收。

掌握了对象存活判定和垃圾标记算法的内容后,下一节我们将深入学习垃圾回收算法的具体实现,进一步完善对本章JVM垃圾回收机制主题的认知。


🍃 系列专栏导航

  • 🔖 专栏导航 深入理解JVM

  • 🔖 JDK5新特性
  • 🔖 JDK8新特性
  • 🔖 JDK11新特性
  • 🔖 JDK17新特性
  • 🔖 JDK21新特性

建议按系列顺序阅读,从基础到进阶逐步掌握核心能力,避免遗漏关键知识点~

其他专栏衔接

  • 🔖 《若依框架全攻略:从入门到项目实战》
  • 🔖 《深入浅出Mybatis》
  • 🔖 全面掌握MySQL工具
  • 🔖 《深入浅出Maven》
  • 🔖 《深入浅出git》
  • 🔖 《深入浅出Kafka》
  • 🔖 《全面掌握Swagger:从入门到实战》
  • 🔖 《Lombok:高效Java开发的秘密武器(完全解读)》
  • 🍃 博客概览:《程序员技术成长导航,专栏汇总》

全景导航博文系列

  • 🔖《一口气学完fastJson》
  • 🔖《一文搞懂PageHelper》
  • 🔖《一文搞懂MyBatis》
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 2:08:09

随时随地远程编程:free-claude-code Discord机器人搭建完整教程

【免费下载链接】free-claude-code Use Claude Code for free in the terminal, VSCode extension, or via Discord 项目地址&#xff1a; https://gitcode.com/gh_mirrors/fre/free-claude-code 点击查看 免费下载 free-claude-code 是一个免费的 Claude Code 代理工具&#…

作者头像 李华
网站建设 2026/10/23 2:07:26

WeSight桌面宠物与像素Studio:给AI Agent工作加一层趣味监控

【免费下载链接】wesight Open-source desktop AI agent workspace with one-click Claude Code, Codex, OpenClaw, Hermes Agent setup and custom LLM model routing. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/we/wesight 点击查看 免费下载 WeSight 是一款开源…

作者头像 李华
网站建设 2026/10/23 2:06:39

面向对象设计原则:SOLID原则详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/23 2:06:33

jQuery EasyUI 1.3.4图标样式修复与覆盖排查指南

简介&#xff1a;面向使用 jQuery EasyUI 1.3.4 的前端开发者与后台管理系统维护者&#xff0c;这套图标与样式素材用于解决界面中按钮、菜单、对话框等元素缺乏统一图形标识的问题&#xff0c;适合快速搭建或完善旧版 EasyUI 项目。压缩包约825KB&#xff0c;核心由预定义图标…

作者头像 李华
网站建设 2026/10/23 2:06:26

HiGHS 线性规划求解器使用指南:安装、求解 LP、QP 与 MIP

HiGHS 线性规划求解器使用指南&#xff1a;安装、求解 LP、QP 与 MIP 【免费下载链接】HiGHS Linear optimization software 项目地址: https://gitcode.com/GitHub_Trending/hi/HiGHS HiGHS 是一款以 C 为主的开源线性规划求解器&#xff0c;能够求解线性规划&#xff…

作者头像 李华