读取文件慢_页面缓存(Page Cache)-内存和文件之间的那点事儿(下)
翻譯:RobotCode俱樂部
現(xiàn)在來(lái)做一個(gè)測(cè)驗(yàn)。假設(shè)render程序的最后一個(gè)進(jìn)程實(shí)例已經(jīng)退出,會(huì)立即釋放頁(yè)面緩存中的scene.dat數(shù)據(jù)?人們經(jīng)常這么認(rèn)為的,但這不是一個(gè)好主意。你有沒有想到,我們通常在一個(gè)程序中創(chuàng)建一個(gè)文件,然后退出,然后在另一個(gè)程序中要使用該文件。頁(yè)面緩存也必須處理這種情況。所以內(nèi)核為什么要?jiǎng)h除頁(yè)面緩存內(nèi)容呢?請(qǐng)記住,磁盤比RAM慢5個(gè)數(shù)量級(jí),因此頁(yè)面緩存命中是一個(gè)巨大的勝利。只要有足夠的空閑物理內(nèi)存,緩存就應(yīng)該被盡可能的使用。因此,它不依賴于特定的進(jìn)程,而是一個(gè)系統(tǒng)范圍的資源。如果你運(yùn)行render進(jìn)程一周后,發(fā)現(xiàn)scene.dat仍然被緩存,這太幸運(yùn)了!這就是為什么內(nèi)核緩存的大小會(huì)穩(wěn)步上升,直到達(dá)到上限。這并不是因?yàn)椴僮飨到y(tǒng)是垃圾并占用你的RAM,這實(shí)際上是一種良好的行為,因?yàn)閺哪撤N程度上說(shuō),釋放物理內(nèi)存才是一種浪費(fèi)。
由于頁(yè)面緩存的存在,當(dāng)程序調(diào)用write()寫字節(jié)時(shí),只需將其復(fù)制到頁(yè)面緩存中,并將頁(yè)面標(biāo)記為dirty。磁盤I/O通常不會(huì)立即發(fā)生,因此你的程序不會(huì)阻塞等待磁盤。不利的一面是,如果計(jì)算機(jī)崩潰,您的寫操作將永遠(yuǎn)無(wú)法完成,因此像數(shù)據(jù)庫(kù)事務(wù)日志這樣的關(guān)鍵文件必須調(diào)用fsync()立刻寫入到磁盤(但是仍然需要擔(dān)心驅(qū)動(dòng)器控制器的緩存,也可能造成并不會(huì)立刻寫入到物理磁盤)。另一方面,讀取通常會(huì)阻塞程序,直到數(shù)據(jù)可用為止。內(nèi)核使用預(yù)先加載技術(shù)來(lái)緩解這個(gè)問題,其中一個(gè)例子是提前讀取,內(nèi)核將幾個(gè)頁(yè)面預(yù)加載到頁(yè)面緩存中,等待你的讀取。你可以通過調(diào)整內(nèi)核的一些選項(xiàng)來(lái)調(diào)整預(yù)先加載行為,可以控制順序讀取文件還是隨機(jī)讀取文件。Linux確實(shí)對(duì)內(nèi)存映射文件進(jìn)行預(yù)讀,但我不確定Windows是否如此。最后,可以在Linux中使用O_DIRECT繞過頁(yè)面緩存,或者在Windows中使用NO_BUFFERING繞過頁(yè)面緩存,這是數(shù)據(jù)庫(kù)軟件經(jīng)常做的事情。
文件映射可以是私有的或共享的。這是針對(duì)內(nèi)存中的內(nèi)容所做的更新:在私有映射中,更新不提交到磁盤或使其他進(jìn)程可見,而在共享映射中,更新是可見的。內(nèi)核使用頁(yè)表項(xiàng)啟用的寫時(shí)復(fù)制機(jī)制來(lái)實(shí)現(xiàn)私有映射。在下面的例子中,render和render3d都私有映射了文件scene.dat。render然后寫入它的虛擬內(nèi)存區(qū)域中的映射文件:
上面所示的只讀頁(yè)表項(xiàng)并不意味著映射是只讀的,它們只是在最后一刻共享物理內(nèi)存的內(nèi)核實(shí)現(xiàn)技巧。你可以看到“private”是多么的不恰當(dāng),只要記住它只適用于更新,讀取不是私有的,也是共享的。這種設(shè)計(jì)的結(jié)果是,通過映射文件的虛擬頁(yè)面可以反映出有其他程序?qū)υ撐募隽烁摹R坏憰r(shí)復(fù)制完成,其他人的更改將不再可見。內(nèi)核不能保證這種行為,但它是在x86中得到的,(是通過硬件方式實(shí)現(xiàn)的?這里不太明白)從API的角度來(lái)看是有意義的。相比之下,共享映射僅僅映射到頁(yè)面緩存,僅此而已。更新對(duì)于其他進(jìn)程是可見的,并最終保存在磁盤中。最后,如果上面的映射是只讀的,那么頁(yè)面錯(cuò)誤將觸發(fā)段錯(cuò)誤,而不是寫入時(shí)的復(fù)制錯(cuò)誤。
動(dòng)態(tài)加載的庫(kù)通過文件映射到程序的地址空間。這沒有什么神奇的,它是同樣的私有文件映射。下面的示例展示了兩個(gè)運(yùn)行實(shí)例部分地址空間中的文件映射,以及物理內(nèi)存使用情況,以便我們將上述許多概念聯(lián)系在一起。
關(guān)于內(nèi)存基礎(chǔ)的3部分系列文章到此結(jié)束。我希望這個(gè)系列是有用的,并為你提供了Linux內(nèi)核內(nèi)存管理的宏觀機(jī)制。
--END
這3部分匯總?cè)缦?#xff1a;
RobotCode俱樂部:程序的內(nèi)存布局(上)
RobotCode俱樂部:程序的內(nèi)存布局(下)
RobotCode俱樂部:內(nèi)核是如何管理內(nèi)存的?(上)
RobotCode俱樂部:內(nèi)核是如何管理內(nèi)存的?(中)
RobotCode俱樂部:內(nèi)核是如何管理內(nèi)存的?(下)
RobotCode俱樂部:頁(yè)面緩存(Page Cache)-內(nèi)存和文件之間的那點(diǎn)事兒(上)
RobotCode俱樂部:頁(yè)面緩存(Page Cache)-內(nèi)存和文件之間的那點(diǎn)事兒(下)
由于本人水平有限,翻譯必然有很多不妥的地方,歡迎指正。同時(shí),歡迎關(guān)注下方微信公眾號(hào),一起交流學(xué)習(xí):)
總結(jié)
以上是生活随笔為你收集整理的读取文件慢_页面缓存(Page Cache)-内存和文件之间的那点事儿(下)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6开头的是什么股票
- 下一篇: 如何进行聚类可视化_如何使用matplo