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

内存区域划分——垃圾回收

一、为什么要有垃圾回收?​

在编程语言发展初期,开发者需要手动管理内存:申请内存空间、使用完毕后手动释放。但这种方式存在两大致命问题:​

  1. 内存泄漏:忘记释放不再使用的内存,导致内存占用持续增长,最终程序崩溃;​
  1. 野指针访问:释放内存后未清空指针,后续误操作该指针会引发程序异常(如崩溃、数据错乱)。​

垃圾回收(Garbage Collection,GC)的核心目标是 自动识别并释放 “无用对象” 占用的内存,解放开发者的内存管理负担,同时避免内存泄漏和野指针问题,保障程序稳定性和内存使用效率。简单说:GC 是内存的 “自动清洁工”,让开发者专注业务逻辑而非底层内存操作。​

二、垃圾回收主要回收哪个内存区域?​

以 Java、Python 等主流语言的内存模型为例,GC 的回收重点是 堆内存(Heap),次要关注方法区(元空间 / 永久代),栈内存(虚拟机栈、本地方法栈)通常不参与 GC。​

  • 堆内存:所有对象实例(如new Object())和数组都存储在堆中,是内存占用最大、对象生命周期最复杂的区域 —— 有的对象仅使用一次就无用,有的则会持续存活到程序结束。GC 的核心工作就是扫描堆内存,筛选出 “死亡对象” 并回收其空间。​
  • 方法区:存储类信息、常量、静态变量等,部分场景下也会产生垃圾(如动态卸载类、常量池过期数据),因此部分 GC(如 Java 的 G1、ZGC)会兼顾方法区的回收。​
  • 栈内存:栈帧随方法调用创建、方法结束销毁,生命周期与线程执行流程强绑定,无需 GC 介入,自动出栈释放。​

结论:堆内存是垃圾回收的 “主战场”。​

三、标记的过程:如何识别 “垃圾对象”?​

GC 的第一步是 “标记”—— 区分 “存活对象” 和 “垃圾对象”,核心逻辑是:可达的对象为存活,不可达的为垃圾。主流标记算法有两种:​

1. 引用计数法(简单但有缺陷)​

  • 原理:给每个对象维护一个 “引用计数器”,被引用时计数器 + 1,引用失效时 - 1;当计数器为 0 时,标记为垃圾。​
  • 优点:实现简单、标记效率高,实时性强(无需暂停程序)。​
  • 缺陷:无法解决 “循环引用” 问题(如 A 引用 B,B 引用 A,两者均无其他外部引用,计数器仍为 1,无法被标记回收),因此主流语言(Java、Python)已弃用。​

2. 可达性分析算法(主流方案)​

  • 原理:以 “GC Roots” 为起点,遍历对象引用链;能被遍历到的对象为 “可达对象”(存活),遍历不到的为 “不可达对象”(垃圾)。​
  • GC Roots 的常见类型:​
  • 虚拟机栈中局部变量表引用的对象(如方法内定义的变量);​
  • 方法区中静态变量、常量引用的对象;​
  • 本地方法栈中 Native 方法引用的对象;​
  • 活跃线程引用的对象。​
  • 优点:能解决循环引用问题,是 Java、C# 等语言的核心标记算法。​
  • 注意:标记过程需要 “暂停用户线程”(Stop The World,STW),避免遍历过程中引用关系变化导致标记错误(后续 GC 优化的核心方向之一是减少 STW 时间)。​

四、回收的过程:如何释放垃圾对象的内存?​

标记完成后,第二步是 “回收”—— 释放垃圾对象占用的内存,同时整理内存碎片(避免碎片过多导致无法分配大对象)。主流回收算法有三种:​

1. 标记 - 清除算法(基础但低效)​

  • 流程:① 标记所有垃圾对象;② 直接清除垃圾对象,释放内存。​
  • 优点:实现简单,无需移动对象。​
  • 缺陷:​
  • 产生大量内存碎片(释放的内存块大小不一,分散在堆中);​
  • 清除效率低(需遍历整个堆查找垃圾对象)。​

2. 标记 - 复制算法(高效无碎片)​

  • 流程:① 将堆内存划分为两个大小相等的区域(From 区和 To 区);② 标记存活对象,将其复制到 To 区;③ 清空 From 区,交换 From 和 To 区的角色(下次回收时 From 区变为 To 区,反之)。​
  • 优点:无内存碎片,回收效率高(只需复制存活对象,存活对象少的时候效率极高)。​
  • 缺陷:堆内存利用率低(仅一半区域可用),适合 “存活对象少、垃圾多” 的场景(如新生代)。​
  • 应用:Java 的 Serial GC、ParNew GC 的新生代回收均采用此算法。​

3. 标记 - 整理算法(适合老年代)​

  • 流程:① 标记所有存活对象;② 将存活对象向堆的一端移动,集中排列;③ 清除堆另一端的所有垃圾对象,释放连续内存。​
  • 优点:无内存碎片,堆内存利用率 100%。​
  • 缺陷:需要移动对象,会增加 STW 时间(移动对象后需更新所有引用该对象的指针)。​
  • 应用:适合 “存活对象多、垃圾少” 的场景(如老年代),Java 的 CMS GC 老年代、G1 GC 均会用到。​

补充:分代收集算法(实际应用的组合方案)​

上述三种算法均有优缺点,因此主流 GC(如 Java 的 HotSpot VM)采用 “分代收集”—— 根据对象生命周期长短,将堆内存分为新生代和老年代,分别使用合适的算法:​

  • 新生代:对象生命周期短(创建后很快成为垃圾),存活对象少 → 用 “标记 - 复制算法”(高效无碎片);​
  • 老年代:对象生命周期长(长期存活),存活对象多 → 用 “标记 - 清除算法” 或 “标记 - 整理算法”(避免频繁复制的开销)。​

五、垃圾回收器的典型实现​

垃圾回收器是 GC 算法的具体工程实现,不同语言、不同虚拟机有不同的实现方案,以下是主流语言的典型 GC:​

1. Java HotSpot VM 的经典垃圾回收器​

Java 的 GC 生态最完善,不同回收器针对不同场景优化:​

  • Serial GC(串行 GC):单线程执行 GC,STW 时间长,适合单 CPU、小型应用(如嵌入式设备),JDK8 默认新生代 GC。​
  • ParNew GC(并行新生代 GC):Serial GC 的多线程版本,新生代用标记 - 复制,老年代需配合 CMS,适合多 CPU 服务器,缩短 STW 时间。​
  • CMS GC(并发标记清除):目标是 “低延迟”,老年代采用并发标记 + 清除(仅初始标记和重新标记阶段 STW),适合对响应时间敏感的应用(如 Web 服务);缺陷是产生碎片、占用 CPU 资源。​
  • G1 GC(区域化分代式):JDK9 及以上默认 GC,将堆分为多个大小相等的 Region(区域),兼顾新生代和老年代回收,采用 “标记 - 整理”+“复制” 混合算法,可预测 STW 时间,适合大堆内存(如 10GB+)。​
  • ZGC/Shenandoah GC(低延迟 GC):专为超大堆、超低延迟设计(STW 时间毫秒级),支持 TB 级内存,适合金融、电商等核心业务。​

2. Python 的 GC 实现​

Python 采用 “引用计数为主,分代回收为辅”:​

  • 日常垃圾回收依赖引用计数,循环引用通过 “分代回收” 解决(将对象分为 3 代,越久未回收的对象扫描频率越低)。​
  • 优点:兼顾简单性和实用性,避免纯引用计数的循环引用问题。​

3. Go 的 GC 实现​

Go 的 GC 是 “并发标记清除 + 三色标记”:​

  • 无需分代,采用三色标记(白色:未标记;灰色:待遍历;黑色:已标记),配合 “写屏障” 避免并发标记时的引用变化,STW 时间极短(Go 1.19 后可控制在微秒级),适合高并发场景。​

六、总结​

垃圾回收的核心逻辑可概括为:通过 “标记” 识别无用对象,通过 “回收” 释放内存,通过 “分代 / 并发” 优化性能。其本质是在 “自动化内存管理” 和 “程序性能” 之间寻找平衡 —— 优秀的 GC 既能解放开发者,又能最小化对程序运行的影响。​

不同语言 / 虚拟机的 GC 实现各有侧重(如 Java 追求通用性,Go 追求低延迟,Python 追求简单性),实际开发中需根据应用场景选择合适的 GC 方案(如大内存应用优先 G1/ZGC,低延迟应用优先 CMS/Shenandoah)。

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

相关文章:

  • 网站建设可行性分析网站开发需求分析用的图
  • Android 无侵入式数据采集:从手动埋点到字节码插桩的演进之路
  • 一致性哈希和普通哈希有什么区别
  • vue 三种类型的插槽
  • TCP的核心特性精讲(上篇)
  • 河源市企业网站seo价格商城网站策划书
  • Spark-3.5.7文档5 - Spark Streaming 编程指南
  • 北京网站关键词优化推荐徐州列表网
  • Spring 事务管理 Transaction rolled back because it has been marked as rollback-only
  • git不想被添加的文件加入到了列表中如何去掉
  • 网关开发笔记
  • 不备案怎么做淘宝客网站吗网站的视频怎么下载
  • 贵阳市住房和城乡建设部网站北京有几个区几个县
  • 【笔记】修复 ComfyUI 启动 ImportError: cannot import name ‘cached_download‘ 错误
  • 长沙网站优化页面学校网站建设工作
  • 昆明企业做网站黎城网站建设
  • 在vue3+uniapp+vite中挂载全局属性方法
  • 地理信息科学 vs 测绘工程:专业区别与就业前景
  • ​​Linux环境下的C语言编程(十六)
  • 淘宝购物返利网站开发基层建设杂志网站
  • 某多多 Redis 面试相关知识点总结
  • 【STM32】知识点介绍三:哈希算法详解
  • Effective STL第8条: 切勿创建包含auto_ptr的容器对象
  • 使用DrissionPage实现虚拟货币市场数据智能爬取
  • 零基础入门C语言之预处理详解
  • 做外汇门户网站重庆相亲网
  • 域名怎么绑定自己网站企业网站如何去做优化
  • Cursor 2.0 扩展 Composer 功能,助力上下文感知式开发
  • C语言应用实例:奋勇争先锋(贪心,qsort用法)
  • 机器学习数学知识温习(2)- 高斯-正态分布