垃圾回收机制GC——SSD如何在“不能覆写“的世界里清理空间?
摘要NAND闪存有一个致命特性——写前必须擦除且擦除的最小单位是块Block不能像HDD那样直接覆盖单个扇区。当空闲块不足时SSD必须在后台执行垃圾回收Garbage Collection将有效数据搬出、再擦除整个块。本文深入解析GC的工作原理、触发机制、Victim Block选择策略、前后台冲突以及TRIM命令如何大幅提升GC效率。一、为什么SSD需要垃圾回收1.1 NAND的不可覆盖困境这是理解GC的核心前提。HDD写入数据时磁头可以直接覆盖旧数据——想改哪个扇区就改哪个。但NAND闪存完全不同┌─────────────────────────────────────────────────────┐ │ HDD vs NAND 写入方式对比 │ ├──────────┬──────────────────┬───────────────────────┤ │ 操作 │ HDD机械硬盘 │ NAND闪存 │ ├──────────┼──────────────────┼───────────────────────┤ │ 写入 │ 直接覆盖 │ 只能写空页空白Page │ │ 修改 │ 直接覆盖原位置 │ 写入新位置 标记旧页无效│ │ 删除 │ 标记删除 │ 标记无效不立即释放 │ │ 擦除 │ 不需要 │ 按Block整体擦除几百页 │ │ 覆写前提 │ 无 │ 必须先擦除整个Block │ └──────────┴──────────────────┴───────────────────────┘关键概念层级Block块 擦除的最小单位通常包含 256~1024 个 Page Page页 写入/读取的最小单位通常 4KB~16KB也就是说哪怕你只想修改Block里一个Page的数据也必须把整个Block的数据搬走、擦除、再重新写入。这就是GC存在的根本原因。1.2 页的四种状态在SSD内部每个Page都处于以下状态之一┌──────────────┬──────────────────────────────────┐ │ 页面状态 │ 说明 │ ├──────────────┼──────────────────────────────────┤ │ Free空闲 │ 从未写过数据可以直接编程Program│ │ Valid有效│ 包含最新有效数据FTL映射表有记录 │ │ Invalid无效│ 数据已过期或被更新但尚未擦除 │ │ Bad坏块 │ 物理损坏永久不可用 │ └──────────────┴──────────────────────────────────┘随着用户不断写入和更新数据Invalid页会越来越多Free页越来越少。当Free页耗尽时SSD就没有空间写入新数据了——GC的作用就是把Invalid页清理掉回收出Free Block。二、垃圾回收的工作原理2.1 GC的基本流程四步走整个过程可以概括为挑选→搬移→擦除→归还Step 1: 选择一个 Victim Block受害者块 ↓ 该块中包含大量 Invalid Page Step 2: 将块中仍然 Valid 的 Page 搬到其他 Block ↓ 这个过程叫数据 rescue救援 Step 3: 擦除整个 Victim Block ↓ 所有 Page 恢复为 Free 状态 Step 4: 将回收的 Block 加入 Free Block Pool ↓ 可以接受新的写入请求用代码逻辑表示defgarbage_collect():# Step 1: 选择 Victim Blockvictimselect_victim_block()# 选择策略见下文# Step 2: 搬移有效数据forpageinvictim.pages:ifpage.statusVALID:new_locationallocate_free_page()write_data(new_location,page.data)update_ftl_mapping(page.lpn,new_location)page.statusINVALID# Step 3: 擦除整个 Blockerase_block(victim)# Step 4: 归还到空闲池victim.statusFREE free_block_pool.append(victim)# 统计这次GC的成本valid_pages_movedcount_valid_pages(victim)gc_costvalid_pages_moved/PAGES_PER_BLOCKreturngc_cost# 越接近0越好2.2 一个具体的例子假设一个Block包含8个Page其中5个已经无效用户更新了数据3个仍然有效GC 前: ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │Valid │Invalid│Valid │Invalid│Invalid│Valid │Invalid│Invalid│ │ 旧A │ 旧B │ 旧C │ 旧D │ 旧E │ 旧F │ 旧G │ 旧H │ └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘ Step 1-2: 搬移3个Valid页到新位置 ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │ →搬走 │ │ →搬走 │ │ │ →搬走 │ │ │ │ 旧A │ 旧B │ 旧C │ 旧D │ 旧E │ 旧F │ 旧G │ 旧H │ └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘ Step 3: 擦除整个Block ┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │ Free │ Free │ Free │ Free │ Free │ Free │ Free │ Free │ └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘ Step 4: 加入 Free Block Pool ✅关键观察GC并不是免费的——它需要额外搬移有效数据产生内部写入。搬移的页越多GC的成本越高。这就引出了GC策略的核心问题如何选择Victim Block使得搬移成本最低三、Victim Block选择策略GC策略的好坏直接影响SSD的性能和寿命。业界有几种经典策略3.1 Greedy贪心策略规则选择Invalid页最多即Valid页最少的Block。Block A: 7 Valid 1 Invalid → GC成本 7/8 87.5% ❌ 太高 Block B: 2 Valid 6 Invalid → GC成本 2/8 25% ✅ 贪心选中 Block C: 4 Valid 4 Invalid → GC成本 4/8 50%优点缺点每次GC回收效率最高忽略了页的年龄冷热搬移数据量最少可能导致热数据被反复搬移实现简单长期来看WAF不一定最优3.2 FIFO先进先出策略规则选择最早被写入的Block最老的Block。Block A: 写入时间 T100s, 5 Invalid → 最老优先回收 Block B: 写入时间 T500s, 3 Invalid Block C: 写入时间 T800s, 7 Invalid优点缺点实现极其简单可能选中Valid页很多的Block不会遗漏老数据GC效率不稳定3.3 Cost-Benefit收益成本策略规则综合考虑Block的Invalid比例和年龄选择收益/成本比最高的。Benefit (Invalid Pages / Total Pages) × (当前时间 - 最后修改时间) Cost Valid Pages需要搬移的代价 Score Benefit / Cost → 选最高的这是理论上最优的策略但计算开销较大。3.4 策略对比总结┌──────────────┬──────────┬──────────┬──────────────┐ │ 策略 │ GC效率 │ 实现复杂度 │ 适用场景 │ ├──────────────┼──────────┼──────────┼──────────────┤ │ Greedy │ ★★★★ │ ★★ │ 消费级SSD │ │ FIFO │ ★★ │ ★★★★★ │ 轻量级固件 │ │ Cost-Benefit │ ★★★★★ │ ★★ │ 企业级SSD │ │ 混合策略 │ ★★★★★ │ ★★★ │ 主流方案 │ └──────────────┴──────────┴──────────┴──────────────┘实际固件中的做法现代SSD通常采用混合策略——先用Greedy快速筛选候选集再用Cost-Benefit做精细排序。部分厂商还会结合温度感知Temperature-aware GC将冷数据Block优先回收。四、前台GC与后台GC4.1 两种GC模式┌─────────────────────────────────────────────────────────────┐ │ GC 的两种执行模式 │ ├──────────────────────┬──────────────────────────────────────┤ │ 前台 GC │ 后台 GC │ │ (Synchronous GC) │ (Asynchronous GC) │ ├──────────────────────┼──────────────────────────────────────┤ │ Free Block 耗尽时 │ SSD 空闲时自动执行 │ │ 被迫停止主机写入 │ 不影响主机正常读写 │ │ 主机感知到延迟 │ 用户完全无感知 │ │ 性能严重下降 │ 提前准备空闲块避免前台GC │ │ SSD变卡的元凶 │ 高端SSD的核心竞争力 │ └──────────────────────┴──────────────────────────────────────┘4.2 为什么用久了SSD会变慢很多用户反映SSD用了一段时间后明显变慢GC是重要原因之一全新 SSD: Free Block 充足 → 所有写入直接落入空闲页 → 无需GC → 速度飞快 使用一段时间后: Free Block 减少 → 写入时需要等待GC回收 → 前台GC触发 → 延迟飙升 典型延迟变化: ┌──────────┬────────────────┐ │ 场景 │ 写入延迟 │ ├──────────┼────────────────┤ │ 全新状态 │ 20-50 μs │ │ 轻度使用 │ 50-100 μs │ │ 重度使用 │ 200-500 μs │ │ 空间耗尽 │ 1000 μs │ ← 前台GC 磨损均衡同时进行 └──────────┴────────────────┘4.3 后台GC的触发时机聪明的固件会在SSD空闲时偷偷执行GC触发条件典型: ① 主机无 I/O 请求超过阈值如 50ms 空闲 ② Free Block 数量低于高水位线如 20% 总块数 ③ SSD 温度低于阈值避免高温下GC加剧发热 ④ 电池/超级电容供电充足防止GC中途断电丢数据 退出条件: ① 收到新的主机 I/O 请求 → 立即暂停GC优先服务主机 ② Free Block 恢复至高水位线以上 ③ 温度超过安全阈值时间轴示意: 主机I/O: ████░░░░░░░░████░░░░████████░░░░░░ 后台GC: ░░░░▓▓▓▓▓▓▓░░░░░▓▓░░░░░░░░▓▓▓▓▓▓ █ 主机写入/读取 ▓ 后台GC ░ 空闲关键洞察好SSD和差SSD的差距很大程度上体现在后台GC的调度策略上。高端固件能让用户几乎感受不到GC的存在而低端固件则频繁触发前台GC导致卡顿。五、TRIM命令GC的效率倍增器5.1 没有TRIM时的问题当用户在操作系统中删除文件时传统流程无TRIM: 用户删除文件 ↓ 操作系统: 在文件系统中标记此文件已删除 ↓ 但是SSD完全不知道哪些数据已经不需要了 ↓ 结果: GC时SSD必须把所有看起来有效的页都当作有效数据搬移 ↓ 大量本可以丢弃的数据被反复搬移 → 写放大严重 ↑↑↑5.2 TRIM的工作原理TRIM在NVMe中称为Dataset Management的Deallocate是操作系统主动告诉SSD这些数据不需要了的机制带TRIM的流程: 用户删除文件 ↓ 操作系统: 标记文件已删除 向SSD发送TRIM命令 ↓ SSD固件: 将对应的逻辑页标记为 Invalid ↓ GC时: 这些页直接被跳过不需要搬移 ↓ 擦除效率大幅提升写放大显著降低 ✅5.3 TRIM的实际效果┌────────────────────────────┬────────────────────┐ │ 场景 │ GC 写放大因子 │ ├────────────────────────────┼────────────────────┤ │ 无 TRIM空间紧张 │ WAF ≈ 5-10x │ │ 无 TRIM空间充裕 │ WAF ≈ 2-4x │ │ 有 TRIM稳态运行 │ WAF ≈ 1.1-1.5x │ │ 有 TRIM Over-Provisioning│ WAF ≈ 1.0-1.2x │ └────────────────────────────┴────────────────────┘5.4 确保TRIM生效的配置Linux系统# 检查SSD是否支持TRIMlsblk--discard/dev/nvme0n1# 检查fstrim定时器是否启用systemctl status fstrim.timer# 手动执行TRIM建议定期运行sudofstrim-v/# 挂载时启用discard实时TRIM但有性能开销# /etc/fstab 中添加 discard 选项UUIDxxx / ext4 defaults,discard01# 更好的方案使用systemd定时器定期批量TRIM# 无需mount选项discard减少实时开销systemctlenablefstrim.timer systemctl start fstrim.timerWindows系统# 检查TRIM是否启用默认开启fsutil behavior query DisableDeleteNotify# 如果返回 0表示TRIM已启用# 如果返回 1手动启用fsutil behaviorsetDisableDeleteNotify 0# 手动优化等同于TRIMOptimize-Volume-DriveLetter C-ReTrim-Verbose⚠️重要提醒RAID阵列中的TRIM支持取决于控制器和驱动。Intel RST、Windows Storage Spaces通常支持但某些硬件RAID卡可能不透传TRIM命令需要特别确认。六、GC与磨损均衡、FTL的协作关系GC不是孤立运行的它和磨损均衡WL、FTL闪存转换层紧密协作┌──────────────────────────────────────────────────┐ │ FTL 核心模块 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │ │ 地址映射 │ │ 磨损均衡 │ │ 垃圾回收 GC │ │ │ │ (L2P) │←→│ (WL) │←→│ │ │ │ └────┬─────┘ └────┬─────┘ └──────┬───────┘ │ │ │ │ │ │ │ └──────────────┼───────────────┘ │ │ ↓ │ │ ┌──────────────┐ │ │ │ 块管理器 │ │ │ │ (Block Mgr) │ │ │ └──────┬───────┘ │ │ ↓ │ │ ┌──────────────┐ │ │ │ NAND 驱动 │ │ │ │ (NAND Flash) │ │ │ └──────────────┘ │ └──────────────────────────────────────────────────┘三者协作时的典型冲突┌──────────────────────────────────────────────────┐ │ 资源竞争场景 │ ├──────────────────────────────────────────────────┤ │ │ │ GC 需要: 空闲块来搬移数据 NAND带宽来擦除 │ │ WL 需要: 空闲块来搬移数据 NAND带宽来写入 │ │ 主机写入: 空闲块来接受新数据 NAND带宽来编程 │ │ │ │ → 三者共享同一块NAND带宽和空间都有限 │ │ → 固件必须在三者之间做出调度权衡 │ │ → 这就是为什么固件开发是SSD最核心的技术壁垒 │ └──────────────────────────────────────────────────┘七、当日知识点小结知识点关键要点GC存在的根本原因NAND写前必须擦除且擦除单位是Block非PageGC四步流程选择Victim Block → 搬移Valid页 → 擦除Block → 归还Free PoolVictim Block策略Greedy效率优先、FIFO简单、Cost-Benefit最优但复杂前台GC vs 后台GC前台触发性能灾难后台执行用户无感知是高端SSD的标志TRIM的作用操作系统主动告知SSD哪些数据已无效大幅降低GC搬移量TRIM配置Linux用fstrim.timerWindows默认启用RAID需确认透传GC与WL/FTL协作三者共享NAND资源调度权衡是固件核心壁垒SSD变慢的原因Free Block不足→前台GC频繁触发→写入延迟飙升 思考题一块SSD有1000个Block每个Block 256个Page。当SSD进入稳态Steady State时假设平均每个Block有60%的页是无效的。如果使用Greedy策略GC一次平均需要搬移多少个Valid页如果改用随机选择策略GC一次平均需要搬移多少个页两者的GC效率差距有多大在Linux系统中为什么社区更推荐用fstrim.timer定期批量TRIM而不是在/etc/fstab中启用discard挂载选项从性能、I/O模式和SSD寿命的角度分析。假设一块消费级SSD的OPOver-Provisioning比例从默认的7%提升到28%类似企业级分析这对GC频率、写放大、可用容量和SSD寿命分别有什么影响。是否存在最佳OP的平衡点️ 推荐标签SSD固态硬盘垃圾回收Garbage CollectionNAND闪存TRIM写放大FTL存储技术固件算法作者持续更新中关注获取每日SSD硬核知识

相关新闻

【NVIDIA】NVIDIA k8s-device-plugin v0.19.3 系统级架构分析

【NVIDIA】NVIDIA k8s-device-plugin v0.19.3 系统级架构分析

NVIDIA k8s-device-plugin v0.19.3 系统级架构分析 分析对象: github.com/k8s-device-plugin-0.19.3 代码语言: Go (116个非vendor Go文件) 分析日期: 2026-07-25 目录 项目整体架构整体设计思路整体运行流程子模块/功能模块划分模块调用关系主流程详解 1. 项目整体架构 1.1 项…

2026/7/25 22:41:55 阅读更多 →
Userspace RCU在实时系统中的应用:低延迟高吞吐的秘密

Userspace RCU在实时系统中的应用:低延迟高吞吐的秘密

Userspace RCU在实时系统中的应用:低延迟高吞吐的秘密 【免费下载链接】userspace-rcu This repo is a mirror of the official userspace-rcu git found at git://git.lttng.org/userspace-rcu.git. liburcu is a LGPLv2.1 userspace RCU (read-copy-update) libra…

2026/7/25 22:40:55 阅读更多 →
跨平台照片同步:digiKam在Linux、Windows和macOS的无缝体验

跨平台照片同步:digiKam在Linux、Windows和macOS的无缝体验

跨平台照片同步:digiKam在Linux、Windows和macOS的无缝体验 【免费下载链接】digikam digiKam is an advanced open-source digital photo management application that runs on Linux, Windows, and MacOS. The application provides a comprehensive set of tools…

2026/7/25 22:40:55 阅读更多 →

最新新闻

AI驱动PPT自动化生成:本地部署与API集成实战指南

AI驱动PPT自动化生成:本地部署与API集成实战指南

这次我们来看一个近期讨论度很高的AI工具组合:GPT-5.6和ppt-master。很多信息把它们混在一起谈,但核心其实是两个独立的东西。先说结论:GPT-5.6并非OpenAI官方发布的模型,而是一个在社区中流传的、据称能力更强的开源模型版本&…

2026/7/25 22:48:59 阅读更多 →
MultiScrollDemo优化指南:解决华为虚拟键适配与屏幕高度动态调整问题

MultiScrollDemo优化指南:解决华为虚拟键适配与屏幕高度动态调整问题

MultiScrollDemo优化指南:解决华为虚拟键适配与屏幕高度动态调整问题 【免费下载链接】MultiScrollDemo NestedScrollViewViewPagerRecyclerViewSmartRefreshLayout 打造酷炫下拉视差效果并解决各种滑动冲突 项目地址: https://gitcode.com/gh_mirrors/mu/MultiSc…

2026/7/25 22:48:59 阅读更多 →
SpringBoot+微信小程序充电桩管理系统毕业设计实战指南

SpringBoot+微信小程序充电桩管理系统毕业设计实战指南

如果你正在为计算机毕业设计发愁,不知道选什么项目既能体现技术实力又符合市场需求,那么充电桩管理系统可能正是你需要的选择。这个项目不仅紧贴新能源汽车行业的发展趋势,还涵盖了SpringBoot后端开发、微信小程序前端、数据库设计、支付集成…

2026/7/25 22:48:59 阅读更多 →
突破Cloudflare Turnstile:使用2captcha-python实现自动验证的完整指南

突破Cloudflare Turnstile:使用2captcha-python实现自动验证的完整指南

突破Cloudflare Turnstile:使用2captcha-python实现自动验证的完整指南 【免费下载链接】2captcha-python Python 3 package for easy integration with the API of 2captcha captcha solving service to bypass recaptcha, сloudflare turnstile, funcaptcha, gee…

2026/7/25 22:48:59 阅读更多 →
机器人逆运动学(IK)到底在算什么?五个关键点从数学本质到工程落地

机器人逆运动学(IK)到底在算什么?五个关键点从数学本质到工程落地

一个"反着问"的问题,为何如此难? 本文出自《具身智能基础》专栏,是本栏目下的第九篇文章,聚焦于逆运动学。 全文 5000 余字,建议收藏阅读。 目录 01 位姿的数学空间:为什么 IK 天然就难 末端…

2026/7/25 22:48:59 阅读更多 →
【管理科学】第五十六篇 企业管理层的权-责-利益分析及权利-人性-资源限制分析01

【管理科学】第五十六篇 企业管理层的权-责-利益分析及权利-人性-资源限制分析01

字段进行深度扩展,详细列出基础数学方程式、组合数学约束方程式、联动方程式以及传递函数方程式,并同步更新参数列表与关联知识。以下为完善后的表格: 编号 类型 行业 企业类型 企业性质 问题(权利-资源-资质-门槛-规则-知识) 数学分析及企业分析及权利-人性-资源限…

2026/7/25 22:47:58 阅读更多 →

日新闻

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解决您的…

2026/7/25 0:00:35 阅读更多 →
C++ string类模拟实现:从深拷贝到内存管理的完整指南

C++ string类模拟实现:从深拷贝到内存管理的完整指南

1. 项目概述:为什么我们要“手撕”string类?在C的学习道路上,尤其是从C语言过渡到C的“初阶”阶段,string类绝对是一个绕不开的核心。标准库里的std::string用起来太方便了,、find、substr,几个操作符和函数…

2026/7/25 0:00:35 阅读更多 →
三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

1. 先搞清楚“三角洲寻宝鼠”到底是什么工具从名称来看,“三角洲寻宝鼠”更像是一个资源查找或文件检索类工具,而不是游戏或娱乐软件。这类工具的核心价值在于帮助用户快速定位特定资源,比如文档、图片、压缩包或特定格式的文件。如果你经常需…

2026/7/25 0:00:35 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/25 5:08:22 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/25 5:13:53 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 18:52:18 阅读更多 →

月新闻