在 Linux 中,我们经常会遇到一个看似矛盾的问题:
一个文件明明只有几十字节,为什么查看磁盘占用时却显示 4KB?
例如:
查看文件大小:
可能显示:
-rw-r--r-- 1 root root 6 Jul 29 19:00 test.txt
说明这个文件只有:
但是:
可能显示:
为什么一个只有 6 字节的文件,却占用了 4KB?
这就涉及 Linux 文件系统中一个非常重要的概念:
文件的逻辑大小和实际占用空间不是一回事。
一、文件系统不会按 byte 存储文件
很多人刚接触计算机存储时,会认为:
这种理解对于文件大小来说没错,但对于磁盘存储来说不准确。
磁盘空间不是按照 byte 一个一个分配的。
Linux 文件系统(例如 ext4)会把磁盘划分成很多固定大小的区域,这些区域叫:block(块)
常见情况下:
也就是:
磁盘结构类似:
磁盘+---------+| block 1 |+---------+| block 2 |+---------+| block 3 |+---------+| block 4 |+---------+...
文件系统分配空间时,以 block 为最小单位。
二、为什么要使用 block?
假设磁盘按照 byte 管理。
一个文件:
只有:
那么文件系统需要记录:
第1个byte在哪里第2个byte在哪里第3个byte在哪里...
如果一个磁盘有几 TB,里面有几十亿甚至几百亿个 byte,这种管理方式效率非常低。
因此文件系统采用更大的管理单位:
例如:
文件只需要记录:
即可。
这样大大降低了管理成本。
三、逻辑大小和实际占用空间
Linux 中,一个文件有两个重要概念:
1. 逻辑大小(文件大小)
也就是:
看到的大小。
例如:
表示文件里面真正的数据有多少。
2. 实际占用空间
也就是:
看到的大小。
例如:
表示这个文件实际占用了多少磁盘空间。
四、为什么说通常是 4KB 的整数倍?
假设 Linux 文件系统 block 大小:
那么一个文件:
需要:
占用:
一个文件:
需要:
占用:
一个文件:
需要:
占用:
原因:
第二个 block 即使只使用 1 byte,也必须整体分配。
因此:
实际占用空间 = block数量 × block大小
所以通常一定是 4096 的整数倍
五、文件尾部的空间浪费
这种现象叫内部碎片(internal fragmentation)
例如一个文件:
block:
分配:
第1个block:4096 byte第2个block:剩余904 byte
但是第二个 block 仍然需要完整占用:
因此实际占用:
其中:
空间没有被使用。
六、为什么 df 和 du 有时候不一致?
Linux 运维中经常遇到:
例如:
显示:
但是:
加起来只有:
可能原因:删除文件仍被进程占用
例如日志文件:
app.log 10GB删除:rm app.log
文件名消失。
但是如果程序仍然打开这个文件,文件数据仍然存在,磁盘 block 不会释放。
查看:
可能看到:
java 1234 app.log (deleted)
重启程序后 block 才会释放。
七、稀疏文件:特殊情况
虽然普通文件通常占用 block 的整数倍,但是 Linux 还有一种特殊文件:
稀疏文件(Sparse File)
例如创建一个:
但是里面大量空间为空。
Linux 可以只分配真正写入的数据 block。
查看:
可能:
但是:
可能:
原因:
逻辑大小:10GB
实际占用:4KB
八、block 和内存 page 的关系
Linux 中还有一个类似概念:内存 page(页)
通常:
磁盘:
两者很像:
原因都是:如果逐 byte 管理,效率太低。
九、运维中如何理解它?
日常 Linux 运维
查看磁盘整体:df -h
关注文件系统整体用了多少 block
查哪个目录占空间:du -sh /*
关注哪些目录占用了大量 block
查看 inode:df -i
关注文件数量是否耗尽
总结
Linux 中,文件大小 ≠ 文件占用磁盘空间
文件大小:
看到的是:
磁盘占用:
看到的是:
由于 Linux 文件系统通常:
所以一个普通 Linux 文件的实际占用空间,通常是 4KB 的整数倍。