命令例如sed
,程式是程序,程式是檔案內的編碼邏輯,而這些檔案位於硬碟上的某個位置。但是,當運行命令時,會從硬碟被放入記憶體,在那裡他們復活並可以做事並被稱為流程。
進程可以使用其他文件,讀取或寫入它們,如果它們這樣做,這些文件稱為開啟文件。有一個命令可以列出所有正在運行的進程打開的所有檔案:lsof
。
好的,所以我想知道的是,命令的雙重生命,一個在硬碟上,另一個在 RAM 中是否也適用於其他類型的文件,例如那些沒有邏輯程式設計的文件,而只是容器資料。
我的假設是,進程開啟的檔案也會載入到 RAM 中。我不知道這是不是真的,這只是一種直覺。
請問有人看得懂嗎?
答案1
不,檔案不會透過開啟而自動讀入記憶體。那將是非常低效的。sed
例如,與許多其他 Unix 工具一樣,逐行讀取其輸入。它很少需要在記憶體中保留比當前行更多的內容。
與awk
它是一樣的。它讀到一個記錄一次,預設為一行。如果將部分輸入資料儲存在變數中,那當然是額外的1。
有些人有這樣的習慣
for line in $(cat file); do ...; done
$(cat file)
由於 shell在運行循環的第一次迭代之前必須完全擴展命令替換for
,因此將要將整個 讀file
入記憶體(讀入執行循環的 shell 使用的記憶體for
)。這有點愚蠢,而且也不優雅。相反,人們應該做
while IFS= read -r line; do ...; done <file
這將逐行處理file
(但請閱讀理解“IFS=讀取-r行”)。
不過,很少需要在 shell 中逐行處理文件,因為大多數實用程式都是面向行的(請參閱為什麼使用 shell 循環處理文字被認為是不好的做法?)。
我從事生物資訊工作,當處理大量基因組資料時,我將無法做太多事情,除非我只將絕對必要的資料位元保留在記憶體中。例如,當我需要從 VCF 檔案中包含 DNA 變體的 1 TB 資料集中剝離可用於識別個體的資料位元時(因為該類型的資料無法公開),我會逐行進行操作使用簡單的awk
程序進行處理(這是可能的,因為VCF 格式是面向行的)。我不要將文件讀入內存,在那裡處理它,然後再次寫回!如果檔案被壓縮,我將透過zcat
or提供它gzip -d -c
,因為gzip
它對資料進行流處理,所以也不會將整個檔案讀入記憶體。
即使文件格式是不是面向行,如 JSON 或 XML,有流解析器可以處理龐大的文件,而無需將其全部儲存在 RAM 中。
對於可執行文件,情況會稍微複雜一些,因為共享庫可以按需加載,和/或在進程之間共享(請參閱共享庫的載入和 RAM 使用情況, 例如)。
快取是我在這裡沒有提到的。這是使用 RAM 來保存經常存取的資料塊的操作。較小的檔案(例如可執行檔)可能會被作業系統緩存,希望使用者能夠多次引用它們。除了第一次讀取檔案之外,後續存取將針對 RAM 而不是磁碟。快取(例如輸入和輸出的緩衝)通常對使用者來說基本上是透明的,並且用於快取內容的記憶體量可能會根據應用程式分配的 RAM 量等動態變化。
1 從技術上講,大多數程式可能一次讀取一塊輸入數據,或者使用顯式緩衝,或者透過標準I/O 庫所做的緩衝隱式地讀取,然後將該區塊逐行呈現給用戶的代碼。讀取磁碟區塊大小的倍數比一次讀取一個字元要高效得多。不過,這個區塊的大小很少會大於幾千位元組。
答案2
然而,當命令運行時,硬碟上的檔案副本會被放入 RAM 中,
這是錯誤的(一般而言)。當程式執行時(透過執行(2)……)進程(運行該程式)正在改變它的虛擬位址空間並且核心正在重新配置記憶體管理單元為了這個目的。另請閱讀有關虛擬記憶體。請注意,應用程式可以使用以下命令更改其虛擬地址空間映射(2)munmap
&&&保護(2),也被使用動態連結器(看ld-linux(8))。也可以看看瘋狂的維斯(2)&posix_fadvise(2)&時脈鎖(2)。
未來頁面錯誤將由核心處理以從可執行檔案載入(延遲)頁面。另請閱讀有關毆打。
內核維護著一個大的頁面緩存。另請閱讀有關寫時複製。也可以看看預讀(2)。
好的,所以我想知道的是,命令的雙重生命,一個在硬碟上,另一個在 RAM 中是否也適用於其他類型的文件,例如那些沒有邏輯程式設計的文件,而只是容器資料。
為了系統調用喜歡閱讀(2)&寫(2)也使用頁面快取。如果要讀取的資料位於其中,則不會執行磁碟 IO。如果需要磁碟IO,讀取的資料很可能會放入頁快取中。因此,在實踐中,如果您運行相同的命令兩次,則可能會發生第二次沒有對磁碟執行任何物理I/O 的情況(如果您有一個舊的旋轉硬碟- 而不是SSD - 您可能會聽到這樣的說法;或仔細觀察硬碟 LED)。
我建議讀一本書,例如作業系統:三個簡單的部分(可免費下載,每章一個 PDF 檔案)解釋了這一切。
也可以看看Linux 吃掉了我的 RAM並執行諸如xosview
、top
、htop
或cat /proc/self/maps
之類的命令cat /proc/$$/maps
(請參閱過程(5))。
附言。我主要關注 Linux,但其他作業系統也有虛擬記憶體和頁面快取。
答案3
不。文件和資料頁活動進程的數量以及緩衝區高速緩存中的檔案資料。
緩衝區快取被刷新,資料頁被換出。且時常頻繁。只讀可執行頁面被覆蓋並標記頁表,因此如果程式再次觸及這些頁面,它們將從檔案系統調入。資料從交換區調入。如上所述,STDIO 庫以區塊的形式提取數據,並由程式根據需要取得:fgetc、fgets、fread 等。是的,您可能有一定程度的控制權,無論它是否在 RAM 中(mlock),但也僅限於此(請參閱 mlock 的錯誤代碼部分)。