1. 程式人生 > >linux 系統 檔案大小不一致的情況分析,檔案空洞

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',即檔案空洞

    容易發生在一個程序在寫一個檔案,這是人工進行清空檔案操作,就會產生。