linux 系統 檔案大小不一致的情況分析,檔案空洞
df 顯示的已使用磁碟佔用率比du 統計出來的結果要大很多。原因,主要是由於兩者計算結果的方式不同。
一、實驗情況
1、建立並刪除檔案
建立檔案前的磁碟容量情況:
# df -h
檔案系統 容量 已用 可用 已用% 掛載點
/dev/sda1 12G 5.7G 5.5G 51% /
tmpfs 506M 0 506M 0% /dev/shm
建立檔案:
# dd if=/dev/zero of=test.iso bs=1024k count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 14.3055 seconds, 73.3 MB/s
現在的磁碟情況:
# df -h
檔案系統 容量 已用 可用 已用% 掛載點
/dev/sda1 12G 6.7G 4.6G 60% /
tmpfs 506M 0 506M 0% /dev/shm
模擬某個程序正在使用該檔案:
# tail -f /tmp/test.iso |
2、刪除該檔案
開啟另一個終端,登陸到系統中。
檢視是否有程序正在使用上面建立的檔案:
# lsof |grep test.iso
tail 2175 root 3r REG 8,1 1048576000 752972 /tmp/test.iso
把該檔案刪掉,並確認:
# rm /tmp/test.iso
rm:是否刪除 一般檔案 “/tmp/test.iso”? y
# ls /tmp/test.iso
ls: /tmp/test.iso: 沒有那個檔案或目錄
檢視是否還有程序在使用(注意結尾的標記):
# lsof |grep test.iso
tail 2175 root 3r REG 8,1 1048576000 752972 /tmp/test.iso (deleted)
檢視磁碟使用情況:
# df -h
檔案系統 容量 已用 可用 已用% 掛載點
/dev/sda1 12G 6.7G 4.6G 60% /
tmpfs 506M 0 506M 0% /dev/shm
# cat /proc/diskstats |grep sda1
8 1 sda1 54385 5184 1626626 130090 20434 635997 5251448 5345733 0 111685 5475829
可見,雖然從ls 已經無法找到該檔案,但因為tail 程序仍在使用該檔案,故實際上核心並沒有把這檔案所佔用的空間釋放出來(df 的結果)。
3、停止相關程序
回到第一終端,用Ctrl+C 終止tail 程序,檢視結果:
# df -h
檔案系統 容量 已用 可用 已用% 掛載點
/dev/sda1 12G 5.7G 5.5G 51% /
tmpfs 506M 0 506M 0% /dev/shm
# cat /proc/diskstats |grep sda1
8 1 sda1 54473 5184 1627402 130617 20453 636042 5251960 5345756 0 112226 5476379
至此,檔案所佔用的空間已完全釋放。
二、說明
從上面的實驗,可得出一些情況:
1、若有程序在佔用某個檔案,而其他程序把這檔案刪掉,只會刪除其在磁碟中的標記,而不會釋放其佔用的磁碟空間;直到所有訪問該檔案的程序退出為止;
2、df 是從核心中獲取磁碟佔用情況資料的,而du是統計當前磁碟檔案大小的結果,由於磁碟標記已被刪掉,因此du 不會計算上述被刪除檔案的空間,導致df 與 du的結果不一致。
三、解決問題
通常的解決方法有兩個:
1、把佔用檔案的相關程序關閉
這可通過下面的命令得到這些已被刪除,但未釋放空間的檔案和程序資訊:
# lsof |grep deleted |
找到這些程序後,在安全的情況下把其關閉,空間自會馬上釋放。
2、以清空的方式替代刪除
歸根到底,產生問題的原因是,訪問該檔案的檔案指標(控制代碼),在rm 動作後,因為程序仍在訪問,因此,仍處在檔案裡面(中間或結尾處)。所以,如果用清空的方式,把檔案指標重置,該檔案所佔用的空間也會馬上釋放出來。
# echo > /tmp/test.iso
# df -h
檔案系統 容量 已用 可用 已用% 掛載點
/dev/sda1 12G 5.7G 5.5G 51% /
tmpfs 506M 0 506M 0% /dev/shm
# tail -f /tmp/test.iso
tail: /tmp/test.iso: file truncated
所以,對於常發生類似問題的檔案,如:日誌記錄檔案等。以改名、清空、刪除的順序操作可避免問題。
四、補充
除rm外,有些不明顯的操作,也會產生類似的問題。
例如 gzip 命令,其對某個檔案xxx.log進行壓縮時,會產生一個新的xxx.log.gz檔案,完成後,會把原來的xxx.log刪除。
這時,若仍有程序在使用xxx.log檔案,那麼,實際上,該檔案還是隻會標記為deleted,其空間也不會釋放,問題與上面提到的情況是相同的。所以,在編寫指令碼時,可先判斷是否仍有程序正在使用該檔案,然後再進行gzip 操作。
五 檔案空洞
檔案讀寫時,如果先檔案指標偏移很大一段,然後寫入1byte;這樣這個檔案實際佔用1byte空間,但是stat檢視檔案大小,或者讀寫時,都會發現檔案很大;所有沒有寫內容的都返回0,且不佔用空間,這樣的檔案叫 'sparse file',即檔案空洞
容易發生在一個程序在寫一個檔案,這是人工進行清空檔案操作,就會產生。