磁盘碎片
概述
- 文件在物理磁盘上被分割存储在非连续扇区,导致读写磁头需要频繁移动
碎片类型
- 内部碎片(
Internal Fragmentation
)- 成因:文件系统固定簇大小(如
NTFS
默认4KB
) - 空间浪费:小文件占用整个簇
- 量化公式:
浪费率 = (簇大小 - 文件大小 % 簇大小) / 簇大小
- 成因:文件系统固定簇大小(如
1 |
| 4KB簇 | 3KB文件 | 1KB空洞 | |
- 外部碎片(
External Fragmentation
)- 成因:文件动态增长导致非连续存储
- 性能影响:
HDD
寻道时间增加20-50ms
/次
1 2 |
磁道示意: [文件A_part1][空闲][文件B][文件A_part2][空闲][文件C] |
文件系统碎片
- 本质
- 一个逻辑连续的文件被分割存储在多个非连续的物理位置
- 形成过程
1 2 3 4 5 6 7 8 9 10 11 12 13 |
初始状态: █████████ 10块连续空间 步骤1: 写入文件A(3块) ███ [A] ███████ 步骤2: 写入文件B(2块) ███ [A] ██ [B] █████ 步骤3: 删除文件A ░░░ [删除] ██ [B] █████ → 自由空间被分割 步骤4: 写入文件C(4块) ▁▁▁ [C1] ██ [B] ██ [C2] ███ → C被碎片化 |
- 文件系统分配单元:
FAT32
:32KB
簇大小NTFS
:4KB
簇大小ext4
:4KB
块大小
- 文件碎片产生条件:
1 2 3 |
if(最大连续自由空间 < 文件所需空间) { 文件被分割存储; // 碎片产生 } |
- 影响表现:
HDD
磁头跳转
单碎片增加8-15ms
寻道时间
1000
碎片文件加载延迟>500ms
SSD
控制器负载
随机读增加20-40% IOPS
垃圾回收效率下降30%
- 文件操作延迟
Windows
:资源管理器响应变慢
数据库:查询时间倍增
自由空间碎片 (空间碎片)
- 本质
- 可用存储空间被分割成大量小型不连续区域
- 形成
1 2 3 4 5 |
初始状态: ██████████████ 完整空间 操作1: 删1,3,5块 → ▓░▓░▓░▓▓▓▓▓▓▓ 操作2: 新文件需4连续块 → 无法分配! 结果: 总空闲9块 ≠ 最大连续3块 |
- 文件系统空闲空间管理方式:
管理方式 | 结构 | 典型系统 |
位图 | 空间块状态矩阵 | NTFS /FAT |
B+ 树 |
空间区间索引 | ext4 /XFS |
链表 | 空闲块链 | 早期系统 |
- 碎片化公式
1 |
空间碎片率 = (总空闲块数 - 最大连续块数) / 总空闲块数 |
- 影响表现:
- 大文件分配失败
1TB
硬盘有900GB
空闲≠
可存500GB
电影
错误:"磁盘空间不足"(实际足够但碎片化) - 写入性能下降
文件系统需多次查找空间块
NTFS
日志记录开销增加300%
- 加剧文件碎片
新文件被强制分段写入
形成碎片连锁反应
- 大文件分配失败
- 影响量化
碎片率 | 性能下降 | 解决难度 |
<10% |
5% 以内 |
简单整理 |
10-30% |
15-40% |
建议整理 |
>30% |
>50% |
需全盘优化 |
>60% |
系统不稳定 | 备份重构 |
文件系统碎片和自由空间碎片对比
- 影响
1
类型 | 影响 | 示例 |
文件碎片 | 降低文件访问速度 | 视频文件被分100 段 |
空间碎片 | 阻碍大文件分配 | 1GB 空间由1000 个1MB 空洞组成 |
- 综合对比
特性 | 文件系统碎片 | 自由空间碎片 |
对象 | 已存在文件 | 未使用空间 |
可见性 | 用户可感知(文件打开慢) | 用户不可见(突发分配失败) |
主影响 | 读取性能 | 写入能力 |
修复方式 | 文件重排 | 空间合并 |
SSD 影响 |
控制器负载 | 写入放大 |
文件碎片检测
- 检测文件的逻辑簇号(
LCN
)分布 ExtentCount > 1
表示存在文件碎片
1 2 3 4 5 6 7 8 9 10 11 12 |
// 使用FSCTL_GET_RETRIEVAL_POINTERS控制码 DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, ...); // 解析返回值获取碎片信息 typedef struct _RETRIEVAL_POINTERS_BUFFER { DWORD ExtentCount; LARGE_INTEGER StartingVcn; struct { LARGE_INTEGER NextVcn; LARGE_INTEGER Lcn; } Extents[1]; } RETRIEVAL_POINTERS_BUFFER; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <winioctl.h> bool isFileFragmented(HANDLE hFile) { STARTING_VCN_INPUT_BUFFER vcnIn = {0}; RETRIEVAL_POINTERS_BUFFER rpBuf; DWORD bytesRet; // 获取文件区块信息 DeviceIoControl( hFile, FSCTL_GET_RETRIEVAL_POINTERS, &vcnIn, sizeof(vcnIn), &rpBuf, sizeof(rpBuf), &bytesRet, NULL ); // 多个Extents表示碎片 return rpBuf.ExtentCount > 1; } |
- 注意:无缓冲
IO
- 作用:绕过系统缓存,直接操作磁盘
- 优势:避免缓存数据与磁盘不一致问题
1 |
CreateFile(..., FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, ...); |
- 注意:内存对齐
- 原理:
SSD
基于页操作(通常4KB
) - 效果:提高
SSD
擦写效率,减少写入放大
- 原理:
1 2 |
// 按4KB边界对齐 const LONGLONG alignSize = (fileSize.QuadPart + 4095) & ~4095; |
- 事务性操作
- 作用:确保文件替换的原子性
- 安全保证:避免系统崩溃导致数据损坏
1 2 3 |
HANDLE hTrans = CreateTransaction(...); MoveFileTransactedW(..., hTrans); CommitTransaction(hTrans); |
碎片整理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
#include <Windows.h> #include <WinIoCtl.h> #include <iostream> #include <vector> #include <string> // 文件碎片整理器核心类 class FileDefragmenter { public: explicit FileDefragmenter(const std::wstring& filePath) : filePath(filePath), hFile(INVALID_HANDLE_VALUE) {} bool Defragment() { if (!OpenFile()) return false; auto fragmentationInfo = GetFragmentationInfo(); if (!fragmentationInfo.first) { CloseFile(); return false; } std::wcout << L"文件当前碎片数: " << fragmentationInfo.second << std::endl; if (fragmentationInfo.second <= 1) { std::wcout << L"文件连续存储,无需整理" << std::endl; CloseFile(); return true; } if (!MoveToContinuousSpace()) { CloseFile(); return false; } CloseFile(); return true; } private: bool OpenFile() { // 获取文件所在卷名 wchar_t volumePath[MAX_PATH]; if (!GetVolumePathNameW(filePath.c_str(), volumePath, MAX_PATH)) { std::wcerr << L"获取卷路径失败: " << GetLastError() << std::endl; return false; } // 打开卷句柄 HANDLE hVolume = CreateFileW( volumePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (hVolume == INVALID_HANDLE_VALUE) { std::wcerr << L"打开卷失败: " << GetLastError() << std::endl; return false; } // 打开文件句柄(带磁盘特权) hFile = CreateFileW( filePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, hVolume ); CloseHandle(hVolume); if (hFile == INVALID_HANDLE_VALUE) { std::wcerr << L"打开文件失败: " << GetLastError() << std::endl; return false; } return true; } std::pair<bool, DWORD> GetFragmentationInfo() { STARTING_VCN_INPUT_BUFFER vcnInput = {0}; std::vector<BYTE> outputBuffer(sizeof(RETRIEVAL_POINTERS_BUFFER) + 64 * sizeof(EXTENT)); DWORD bytesReturned = 0; if (!DeviceIoControl( hFile, FSCTL_GET_RETRIEVAL_POINTERS, &vcnInput, sizeof(vcnInput), outputBuffer.data(), static_cast<DWORD>(outputBuffer.size()), &bytesReturned, NULL)) { std::wcerr << L"获取碎片信息失败: " << GetLastError() << std::endl; return {false, 0}; } auto retrievalBuffer = reinterpret_cast<RETRIEVAL_POINTERS_BUFFER*>(outputBuffer.data()); return {true, retrievalBuffer->ExtentCount}; } bool MoveToContinuousSpace() { // 1. 创建临时文件 std::wstring tempPath = filePath + L".tmp"; HANDLE hTemp = CreateFileW( tempPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, NULL ); if (hTemp == INVALID_HANDLE_VALUE) { std::wcerr << L"创建临时文件失败: " << GetLastError() << std::endl; return false; } // 2. 预分配连续空间 LARGE_INTEGER fileSize; if (!GetFileSizeEx(hFile, &fileSize)) { std::wcerr << L"获取文件大小失败" << GetLastError() << std::endl; CloseHandle(hTemp); return false; } // 按4K对齐调整大小(SSD优化) const LONGLONG alignSize = (fileSize.QuadPart + 4095) & ~4095; fileSize.QuadPart = alignSize; if (!SetFilePointerEx(hTemp, fileSize, NULL, FILE_BEGIN) || !SetEndOfFile(hTemp)) { std::wcerr << L"预分配空间失败" << GetLastError() << std::endl; CloseHandle(hTemp); return false; } // 3. 文件复制(使用高效API) LARGE_INTEGER offset = {0}; const DWORD bufferSize = 4 * 1024 * 1024; // 4MB缓冲区 std::vector<BYTE> buffer(bufferSize); DWORD bytesRead = 0, bytesWritten = 0; while (offset.QuadPart < fileSize.QuadPart) { // 偏移量对齐 LARGE_INTEGER alignedOffset; alignedOffset.QuadPart = offset.QuadPart & ~(4095LL); SetFilePointerEx(hFile, alignedOffset, NULL, FILE_BEGIN); // 使用无缓冲IO读取 if (!ReadFile(hFile, buffer.data(), bufferSize, &bytesRead, NULL) || bytesRead == 0) { break; } // 计算实际有效长度 DWORD validSize = static_cast<DWORD>(min( static_cast<LONGLONG>(bytesRead), fileSize.QuadPart - offset.QuadPart )); // 写入临时文件 SetFilePointerEx(hTemp, offset, NULL, FILE_BEGIN); if (!WriteFile(hTemp, buffer.data(), validSize, &bytesWritten, NULL) || bytesWritten != validSize) { std::wcerr << L"写入临时文件失败" << GetLastError() << std::endl; CloseHandle(hTemp); return false; } offset.QuadPart += validSize; } // 4. 文件替换 CloseHandle(hFile); CloseHandle(hTemp); if (!ReplaceOriginalWithTemp(filePath, tempPath)) { return false; } return true; } bool ReplaceOriginalWithTemp(const std::wstring& original, const std::wstring& temp) { // Windows事务性文件替换 HANDLE hTrans = CreateTransaction(NULL, 0, 0, 0, 0, 0, L"DefragTransaction"); if (hTrans == INVALID_HANDLE_VALUE) { std::wcerr << L"创建事务失败" << GetLastError() << std::endl; return false; } if (MoveFileTransactedW( temp.c_str(), original.c_str(), NULL, MOVEFILE_REPLACE_EXISTING, hTrans) == 0) { std::wcerr << L"移动文件失败" << GetLastError() << std::endl; RollbackTransaction(hTrans); return false; } if (!CommitTransaction(hTrans)) { std::wcerr << L"提交事务失败" << GetLastError() << std::endl; RollbackTransaction(hTrans); return false; } CloseHandle(hTrans); return true; } void CloseFile() { if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); hFile = INVALID_HANDLE_VALUE; } } std::wstring filePath; HANDLE hFile; }; int wmain(int argc, wchar_t* argv[]) { if (argc < 2) { std::wcout << L"用法: Defragmenter.exe <文件名>" << std::endl; return 1; } // 仅对HDD磁盘运行 wchar_t driveRoot[4] = { argv[1][0], L':', L'\\', 0 }; UINT driveType = GetDriveTypeW(driveRoot); if (driveType == DRIVE_FIXED) { // 检测是否SSD DWORD perfFlags = 0; if (DeviceIoControl( GetVolumeHandle(driveRoot), IOCTL_DISK_PERFORMANCE, NULL, 0, &perfFlags, sizeof(perfFlags), NULL, NULL)) { if (perfFlags & PERF_MODE_SSD) { std::wcout << L"警告:SSD无需碎片整理!" << std::endl; return 0; } } } FileDefragmenter defragmenter(argv[1]); if (defragmenter.Defragment()) { std::wcout << L"文件整理成功!" << std::endl; return 0; } std::wcout << L"文件整理失败!" << std::endl; return 1; } |
碎片整理的总结
- 机械
- 必须定期碎片整理
HDD
依赖物理磁头寻道读取数据
文件碎片化会导致磁头频繁跳动(寻道时间增加8-15ms/
次),大幅降低读写速度
- 固态
- 禁止碎片整理
SSD
通过电子信号直接访问闪存单元,无机械寻道过程,碎片化不影响读取速度- 碎片整理需多次擦写数据,消耗闪存颗粒的
P/E
擦写次数 1
次全盘整理可能损耗SSD 0.1%
寿命,频繁操作显著缩短使用寿命
- 固态优化方案
- 启用
TRIM
- 系统自动标记无效数据块,提升垃圾回收(
GC
)效率,维持高性能
- 启用
1 2 3 4 5 6 |
// 查询 fsutil behavior query DisableDeleteNotify // 0:TRIM已启用 // 1:TRIM未启用 |
1 2 3 |
// 启用 fsutil behavior set DisableDeleteNotify 0 |
1 2 3 4 5 |
C:\Users\wangx>fsutil behavior query DisableDeleteNotify NTFS DisableDeleteNotify = 0 (允许将 TRIM 操作发送到存储设备) ReFS DisableDeleteNotify = 0 (允许将 TRIM 操作发送到存储设备) C:\Users\wangx> |
整理整个磁盘
1 2 3 4 5 6 7 8 9 10 |
// 使用系统碎片整理API #include <Dfshl.h> HRESULT hr = DefragFileEx( volumeRoot, // 如L"C:\" filePath, // 单个文件路径 NULL, // 进度回调 NULL, // 回调参数 DF_GET_FRAGMENT_STATS | DF_APPLY_DEFRAG // 操作标志 ); |
文件系统:FAT
系列(File Allocation Table
)
FAT16
- 最大分区
2GB
,单个文件≤4GB
- 兼容性极强(
DOS/Win95
) - 簇大小固定(默认
64KB
),小文件存储效率低
FAT32
- 分区上限
2TB
,文件仍≤4GB
- 簇大小优化(
4KB-32KB
),空间浪费减少 - 支持
Win98
及后续系统,但无权限控制
exFAT
(Extended FAT
)
- 突破文件限制(
16EB
),分区达128PB
- 专为闪存设计:支持
32MB
大簇、ECC
校验、TRIM
指令 - 适用大容量移动设备(相机/
SD
卡)
文件系统:NTFS
(New Technology File System
)
优势
- 支持
256TB
分区 +16TB
文件(理论值) - 日志功能:崩溃后快速恢复
- 权限控制(
ACL
)、加密(EFS
)、压缩
创新技术
MFT
主文件表:元数据集中管理- 自修复机制:自动替换坏扇区
- 簇大小灵活(
4KB-64KB
)
使用
- 默认用于
Windows
系统盘及企业存储
文件系统:现代高性能文件系统
ReFS
(Resilient File System
)
- 设计目标:
- 数据中心级可靠性与扩展性
- 关键技术
- 完整性流:元数据+数据双校验
- 块克隆:快速复制大文件(如虚拟机镜像)
- 镜像加速奇偶校验:混合
SSD+HDD
性能优化
- 特点
- 支持
35PB
超大卷,专攻虚拟化/备份场景
- 支持
ZFS
(Zettabyte File System
)
- 颠覆性架构
- 存储池化:物理设备虚拟为统一资源池
- 写时复制(
CoW
):杜绝数据崩溃风险 - 端到端校验:自动修复静默数据损坏
- 高级功能:
- 实时去重 + 压缩:节省存储成本
- 快照/克隆:秒级创建数据副本
- 使用
- 主要用于
FreeBSD/Linux
服务器及NAS
系统
- 主要用于
文件系统:开源生态文件系统
ext4
(Fourth Extended Filesystem
)
Linux
默认系统,支持1EB
分区 +16TB
文件- 日志分层:保障元数据一致性
- 延迟分配:减少碎片,提升大文件写入速度
Btrfs
(B-Tree Filesystem
)
- 对标
ZFS
:集成快照、RAID
、校验和 - 动态卷管理:在线调整分区大小
- 适用于
Linux
桌面/服务器
机械硬盘(HDD
)物理结构
磁道
- 同心圆结构
- 每个盘片表面被划分为多个同心圆环,每个环称为一个磁道
- 磁道从盘片最外圈开始编号(
0
磁道),向内逐圈递增
- 磁道密度
- 单位长度内的磁道数量称为道密度(单位:
TPI
,磁道数/英寸) - 现代硬盘磁道密度可达
1,100 Gb/in²
以上(如20TB
硬盘约1,146 Gb/in²
)
- 单位长度内的磁道数量称为道密度(单位:
- 技术演进:
- 传统硬盘:所有磁道的扇区数相同,导致外圈存储密度低、空间浪费
- 现代硬盘(
ZBR
技术):外圈磁道扇区数多于内圈(如外圈扇区数是内圈的2倍),实现等密度存储,提升容量利用率
扇区
- 最小存储单位:
- 每条磁道被划分为若干弧段,每个弧段称为一个扇区
- 扇区是硬盘读写的最小单元,传统大小为
512
字节,现代先进格式硬盘支持4,096
字节(4K
)
- 扇区编号规则:
- 物理扇区:通过绝对地址(柱面号
C
、磁头号H
、扇区号S
)定位,例如(C=0, H=0, S=1)
对应第一个物理扇区(主引导记录MBR
) - 逻辑扇区(
LBA
):为简化寻址,操作系统将物理扇区线性编号(从0
开始)
- 物理扇区:通过绝对地址(柱面号
1 2 3 |
LBA=(C×磁头数+H)×每道扇区数+(S−1) // 例如:柱面号C=5、磁头号H=2、扇区号S=3,若磁头数=8、每道扇区数=63,则 LBA = (5×8+2)×63 + 2 = 2,552 |
机械硬盘核心物理结构
- 关键参数
- 盘片转速:
5400/7200/15000 RPM
- 扇区大小:
512B/4KB
(先进格式) - 磁头飞行高度:
3-5
纳米(头发直径的1/10000
)
- 盘片转速:
读取文件详细流程
- 以读取
C:\data.txt
(存储在物理扇区LBA=1000
)为例: - 步骤1:操作系统发起请求
- 触发:文件系统将逻辑位置转换为物理地址
- (
NTFS
的MFT
定位 → 扇区1000-1007
)
1 |
ReadFile(hFile, buffer, 4096); // 请求读取4KB数据 |
- 步骤2:硬盘控制器处理指令
1 2 |
; 控制器将LBA转换为CHS地址 LBA 1000 → Cylinder=5, Head=0, Sector=8 |
- 步骤3:机械部件协同工作(耗时核心)
- 寻道(
Seek Time
):
磁头臂移动到第5
柱面(最耗时)
平均寻道时间:7200RPM
硬盘约9ms
- 旋转延迟(
Rotational Latency
):
盘片旋转直到目标扇区到达磁头下方
平均延迟:7200RPM
硬盘约4.17ms
(半圈时间) - 数据传输(
Transfer
):
数据传输速度:约150MB/s
(SATA III
接口)
- 寻道(
- 步骤4:数据返回至操作系统
写入文件详细流程
- 以覆盖写入
D:\log.txt
(目标扇区LBA=2000
)为例: - 步骤1:操作系统发起请求
1 |
WriteFile(hFile, newData, 8192); // 写入8KB数据 |
- 步骤2:硬盘预处理
- 缓存写入:
数据先存入硬盘DRAM
缓存(64-256MB
)
返回"写入成功"(操作系统以为完成) - 磁盘调度算法
控制器合并相邻写入请求
电梯算法(SCAN
):减少磁头摆动
- 缓存写入:
- 步骤3:物理写入(关键延迟)
- 预写补偿:内圈磁道写入电流增强
- 飞写技术:磁头扫过时瞬间磁化
- 数据编码:采用
RLL
(游程长度受限) 编码节省空间
- 步骤4:缓存刷新
- 关机/异常时:未刷新的缓存数据丢失风险
- 解决方案:启用
Write Barrier
或UPS
电源保护
固态硬盘(SSD
)物理结构
NAND
闪存芯片
- 存储单元(
Memory Cell
):- 基本结构为“工”字形 电荷陷阱(
Charge Trap
),使用氮化硅捕获电子 - 电荷量表示数据(如
SLC
:1bit/
单元,TLC
:3bit/
单元,QLC
:4bit/
单元)
- 基本结构为“工”字形 电荷陷阱(
- 层级组织:
String
:纵向串联的存储单元,共享位线(BitLine
)Page
:横向单元组(4KB~16KB
),读写最小单位Block
:由100~200
个Page
组成(如512KB
),擦除最小单位
控制器(Controller
)
- 核心功能
FTL
(闪存转换层):逻辑地址→物理地址映射- 磨损均衡(
Wear Leveling
):平均分配写入次数 - 垃圾回收(
GC
):回收无效数据空间
DRAM
缓存- 加速映射表(
Page Mapping Table
)访问
- 加速映射表(
- 接口电路
SATA/NVMe
协议:数据传输通道(如PCIe 4.0
带宽达8GB/s
)
读取文件详细流程
- 以读取逻辑地址
LBA=X
为例: - 操作系统请求:
- 文件系统(如NTFS)将文件位置转换为逻辑块地址(LBA)
- 控制器处理:
- 查询 页映射表(
Page Mapping Table
),找到LBA
对应的物理页号 - 例如:
LBA=1000 → 物理页 Block5-Page8
- 查询 页映射表(
- 闪存读取操作:
- 激活控制栅(
Control Gate
):选中目标String
中的单元 - 电荷检测:测量阈值电压,判断电荷量(如
0V→"111"
,3V→"000"
) - 数据输出:通过位线(
Bit Line
)并行传输整个Page
数据至缓存
- 激活控制栅(
- 返回数据:
- 数据经接口返回操作系统,耗时微秒级(比
HDD
快100
倍)
- 数据经接口返回操作系统,耗时微秒级(比
写入文件详细流程:新数据写入
- 分配空闲页:
FL
查找空闲页(如Block8-Page12
),更新映射表
- 数据编程:
- 电荷注入:高压将电子注入浮栅,写入数据(如
"010"
) - 多阶段验证:循环校验确保电荷稳定(防写入错误)
- 电荷注入:高压将电子注入浮栅,写入数据(如
- 返回成功:
- 数据写入
DRAM
缓存后即返回,实际落盘稍后完成(异步写入)
- 数据写入
写入文件详细流程:覆盖写入(更新数据)
- 标记旧页无效:
- 原物理页(如
Block3-Page4
)标记为失效,但暂不擦除
- 原物理页(如
- 写入新页:
- 分配新空闲页(如
Block9-Page1
),写入更新后数据
- 分配新空闲页(如
- 更新映射表:
- 逻辑地址重定向至新页,旧页加入
GC
候选
- 逻辑地址重定向至新页,旧页加入
写入瓶颈:垃圾回收(GC
)
- 当空闲页不足时触发:
- 选择待回收
Block
:包含最多无效页的块(如60%
无效) - 迁移有效数据:将有效页复制到新
Block
(如BlockX
→BlockZ
) - 擦除原
Block
:高压清除全部电荷,恢复为空闲块 - 更新映射表:有效数据的新物理地址更新
- 选择待回收
问题
- 机械,固态都是存在非连续扇区
SSD
无传统扇区概念:
SSD
最小存储单元为页(4KB~16KB
),最小擦除单元为块(512KB~4MB
)
- 所以一份文件在逻辑上是连续的,在物理上可能不是连续的?
- 文件在逻辑上(操作系统视角)是连续的
文件被看作连续的字节流,每个文件被赋予逻辑块地址(LBA
)范围(如LBA=1000~2000
表示连续2KB
文件)
文件系统(如NTFS/ext4
)的职责:
维护文件逻辑位置与LBA
的映射关系(如通过MFT
或inode
记录:data.txt
占据LBA 1000-2000
)
向硬盘控制器发送连续的读写指令(如:从LBA=1000
开始顺序读取1001
个块) - 但在物理层面(硬盘实际存储位置)完全可能是非连续的
- 文件在逻辑上(操作系统视角)是连续的
- 如果文件动态增长,一定会导致碎片化吗
- 文件动态增长不一定导致碎片化,其是否产生碎片取决于文件系统策略、硬盘类型及写入模式,如下:
- 文件系统预留机制(关键防御)
现代文件系统(NTFS/ext4/Btrfs
)采用 "扩展分配(Extents
)" 技术,预先分配连续空间 - 延迟分配技术(
Delayed Allocation
)
文件系统先记录写入请求,积累到大块数据(如4MB
)后一次性分配物理空间
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Windows 核心编程 _ 进程四06/25
- ♥ Windows创建进程实例:权限及子进程监控相关10/19
- ♥ Windbg:命令实践详解一03/27
- ♥ Windows 核心编程 _ 用户模式:线程同步二07/16
- ♥ Windows 核心编程 _ 进程二06/19
- ♥ Windows 核心编程 _ 线程内幕07/06