虽然这里通过清空文件暂时解决了磁盘未释放的问题,但是从根本上我们最好还是要避免这种问题的出现,比如协调好多进程间对于文件操作的时序问题,比如等到进程A结束了对文件的访问,进程B再去删除文件。
3 原因分析
下面我们从操作系统层面简单分析一下出现这种现象的原因:
在 Linux 文件系统中,一个文件由目录项、索引节点和数据块三部分组成。
- 目录项,也就是 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。多个目录项关联起来,就会形成目录结构,但它与索引节点不同的是,目录项是由内核维护的一个数据结构,不存放于磁盘,而是缓存在内存。
- 索引节点,也就是 inode,用来记录文件的元信息,比如 inode 编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等等。索引节点是文件的唯一标识,它们之间一一对应,也同样都会被存储在硬盘中,所以索引节点同样占用磁盘空间。
- 数据块,包含文件的具体内容,存储在硬盘上,硬盘的最小存储单位是扇区(Sector),然而扇区只有 512字节大小,如果每次都读写这么小的单位效率一定很低,所以当操作系统从硬盘读取数据的时候,不会一个个扇区的地去读取,而是一次性连续读取多个扇区,即一次性读取一个”块“(block) 由多个 sector 组成的 block ,是文件存取的最小单位 ,block 常见大小的是 4KB,即连续 8 个 sector 组成一个 block。
既然文件数据都存储在 block 中,那么我们指定读取某个文件数据的时候,操作系统就需要知道这个文件存储在哪个 block 上 ,而文件的数据存放位置信息被存放到了 inode 上,所以我们先要找到这个文件对应的inode号。使用stat命令可以查看inode信息:
以我们访问上面的test.bin文件为例,会经过以下步骤:
1)系统在目录项中根据文件名找到对应的 inode 号
2)通过 inode 号获取到 inode 信息
3)根据 inode 信息找到文件数据所在的 block ,读出数据
inode 跟数据块一样会消耗硬盘空间,所以硬盘格式化的时候,系统自动将硬盘分成2个区域:
- 一个是数据块,存放文件数据
- 另一个是 inode 区,存放 inode 所包含的信息,即文件元信息
了解了文件的存储结构之后,我们来看下对文件执 rm 行删除操作之后,这两个部分会发生什么。
文件被删除的时候,文件对应的 inode 就被删除掉了,而文件的数据部分在 inode 被清除掉之后,就会被覆盖并写入新的内容。但是如果文件在删除的时候是被打开的状态,比如有一个进程正在使用该文件,文件被进程锁定或者有进程一直在向这个文件写数据等,那么进程依旧可以读取该文件,系统就会认为该文件并未删除,导致磁盘空间一直被占用。