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