如果讀取硬碟上某個文件,使用完畢後釋放內存,然後立即再讀取這個文件,會從內存中還是從硬碟上再讀取?

我面臨的問題是,如果我有一個程序有10000張100k大小的圖片,可能會用到,但是不能全部載入內存,我可以取三種做法:

一,使用任何一張圖都載入,使用完之後不釋放,系統最終內存不足,系統會自動將長期不用的那一段內存寫到硬碟上,下次使用到時再重新載入內存,這叫虛擬內存。

二,維護一個隊列,隊列內有100張最近使用的圖片,每張圖片被使用之後就提到隊列最前,如果使用的圖片不在隊列中,從硬碟中讀取,然後加到隊列第一位,並釋放隊列中最後的那張圖片佔用的內存,這樣手動維持一個緩存機制。

三,使用任何一張圖都載入,使用完就釋放,依賴系統緩存機制,希望下一次從硬碟上讀取這一張圖片時,系統會從剛才釋放的內存中讀取,不對硬碟進行讀取操作。

請問第三種思路,這種系統緩存機制普遍存在嗎?還是不普遍存在?

以上三種做法哪一種最好,最合理?


你直接讀文件就行,讀過後文件的內容會在standby list的內存頁中,然後windows會統一管理這個standby list決定何時丟棄。這個緩存機制是跨進程的。

當然你也可以自己再申請一塊內存,把文件內容讀到這裡面,這時候就等於就兩層緩存了,第一層是你自己申請的內存(可以是heap上的,也可以是VirtualAlloc出來的),第二層還是windows內核管理的standby list。

如果你覺得這樣兩層緩存太浪費,也可以在讀文件的時候指定no cache,這樣就只有你自己控制的那層緩存了。

具體哪個好就很難說了,可能造成影響的因素太多了。

像SQL Server這樣的應用是自己分配一塊物理內存來自己控制緩存的,不用windows的機制。


我在編寫圖片數據標註軟體的過程中遇到過一樣的問題。

解決方案是:

1) 手動維護緩存池保留最近使用的若干圖片。使用最近未使用演算法替換。

2) 載入圖片時根據空間局部性載入多張圖片。訪問到不在緩存池中的圖片時,一次性載入該圖及其相鄰的圖片。(如做人臉標註時同時載入該人若干張其它照片。)

3) IO線程與GUI線程分開。

使用效果非常流暢,連續的切換圖片就像放視頻一樣,基本不卡頓。


會有這幾個緩存:

(1)driver級緩存:比如你說的硬碟driver上分配的內核緩存,一般為了加快連續讀取速度減少IO訪問,可以說是一些driver工程師「惡意」添加的,只對讀有效,沒辦法清除不用。

(2)FS級緩存:同樣是減少直接IO訪問的,主要是file map的內核緩存,對讀寫都有效,不過可控,可以drop cache或者sync強制fs commit。

(3)user級緩存:自己可控就是你的free部分。


方式2最好,但也需要設計好演算法。

程序讀取一張圖片,先到內核,再到用戶態,

內核緩存是文件系統和IO子系統控制的,

所以要優化的話,只能優化用戶態的緩存, 除非你的程序是內核級的。

用戶態的話,可以優化你的緩存隊列。如前面莫濤所言,

具體怎麼優化由你的「可能會用到」這個條件決定,

即到底什麼情況下會被用到,就緩存這些case。


推薦閱讀:

多核CPU中,利用多線程進行排序中出現了一些奇怪的現象,不知道其背後的原因是什麼,希望有人能給予解答?
Linux內核是如何管理內存的換入換出,以及是如何實現磁碟緩存的?
微軟在 Windows 10 裡面加入 Linux,這是他們認輸了嗎?
實現一個shell解釋器需要哪些編譯原理方面的知識?
為什麼WinXP的驅動無法用於Win7、Vista,但是Win7,Vista驅動可用於Win10?

TAG:操作系統 | 緩存 | 系統緩存 |