Linux下查看磁盘空间使用情况,最常使用的是du和df。有一次du和df统计的磁盘分区大小不一致,这是为什么呢?二者有什么区别?网上搜索下,大神早有总结,实践后汇总学习下。
du的工作原理
du对待统计文件逐个系统调用fstat,获取文件大小。它的数据是基于文件获取的,所以有很大的灵活性,不一定非要针对一个分区,可以跨越多个分区操作。如果针对的目录中文件很多,du速度就会很慢了。
1.如果统计目录下挂载了其他文件系统,那么也会对这个文件系统进行统计。计算时记得将这一部分从总和中去掉。
2.如果文件被删除,即使被其他进程引用了,du命令也无法对其统计。因为stat命令找不到这个文件。
3.可以跨分区统计某些你想统计的文件大小总和。因为它们都能被stat找到并统计。
df的工作原理
df使用系统调用statfs,直接读取分区的超级块superblock信息来获取分区使用情况。它的数据是基于分区元数据的,所以只能针对整个分区。由于df直接读取超级块(superblock才占用1024字节),所以运行速度不受文件多少影响。
1.当某个文件系统下挂载了其他分区,df不会把这个分区也统计进去。
因为df读取的是各自分区的superblock,即使分区1挂载在分区0的目录下,df统计分区0的时候,也只能读取分区0的superblock。
2.由于df每次统计都是读取superblock,所以df对文件系统中的某个文件进行统计时,会自动转为统计这个文件系统(分区)的信息。也就是说,df通过文件找到对应的分区挂载点。
[root@xuexi ~]# df -hT /etc/fstab
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda2 ext4 18G 1.7G 15G 11% /
3.df会统计因子挂载点而被隐藏的原目录文件大小。
如果在/mnt目录下有3G的文件,然后在/mnt上挂载了其他文件系统,/mnt下原本那3G的文件就被隐藏起来无法访问,du无法统计这部分数据大小(但du会统计挂载在/mnt上的文件),但df会统计这部分信息。
4.df会统计已删除但却仍有进程引用的文件。
正常情况下,删除文件会立刻释放相关指针,并将imap和bmap中相关的位图标记为未使用。bmap只要一改变,文件系统立刻就能知道每个块组中哪些数据块是空闲的,哪些数据块是被使用的,这些信息都会更新到分区的superblock中。于是df能立刻统计到实时的磁盘空间信息。读写文件的过程以及涉及的imap和bmap,后面再研究。
du和df不一致情况
常见的df和du不一致情况是文件删除的问题。当一个文件被删除后,在文件系统目录中已经不可见了,所以du就不再统计它。然而如果此时还有运行的进程持有这个已经被删除文件的句柄,这个文件就不会真正在磁盘中被删除, 分区超级块中的信息也就不会更改。这样df仍旧会统计这个被删除了的文件。
在home下创建一个1G大小的文件test.log,df -h /home和du -sh --max-depth=1 /home查看磁盘空间占用情况。
tail -f test.log &,然后rm -rf test.log。
# lsof | grep test.log
tail 23955 root 3r REG 8,1 1048576000 7999 /home/test.log (deleted)
使用df -h /home和du -sh --max-depth=1 /home再次查看磁盘空间占用情况。发现df没有变化,而du则不再统计被删除了的文件test.log。
停止进程23955,使用df和du再次查看,数据一致了。
二者区别
du是用户级的程序,它不考虑Meta Data,而df命令则查看文件系统的磁盘分配图并考虑Meta Data。df命令获得真正的文件系统数据,而du命令只查看文件系统的部分情况。
参考资料
网友评论