瀏覽器應該使用所有的可用內存嗎?

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"},{"type":"color","attrs":{"color":"#333333","name":"user"}},{"type":"strong"}],"text":"本文最初發佈於 "},{"type":"text","marks":[{"type":"italic"},{"type":"strong"}],"text":"Julio Merino 的個人"},{"type":"text","marks":[{"type":"italic"},{"type":"color","attrs":{"color":"#333333","name":"user"}},{"type":"strong"}],"text":"博客,經原作者授權由 InfoQ 中文站翻譯並分享。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"這篇文章在我的草稿箱裏呆了 3 年了。我之所以一直猶豫着沒發,一部分原因是本文探討的內容是一個比較難以達成共識的想法。另一部分原因是,如果只看這個激進的標題,可能會引發不小的爭議。無論如何,現在是時候發佈出來了!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"根據"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/Betteridge%27s_law_of_headlines","title":null,"type":null},"content":[{"type":"text","text":"Betteridge的標題法則"}]},{"type":"text","text":",標題中的問題,答案一般是“不“。我同意,但有一些點需要注意。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們都見過類似這樣的討論,尤其是在 Hacker News 上:首先是有人抱怨,像谷歌 Chrome 這樣的應用程序很浪費資源,因爲它會消耗好幾 GB 的內存。然後就有人過來說,這些內存是用來提升速度的,因此,這是正確的行爲:如果計算機有數 GB 的空閒內存,像 Chrome 這樣的應用程序應該將所有可用內存用作緩存,從而儘可能地提高響應速度。好像很有道理,是嗎?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是的,有道理,"},{"type":"text","marks":[{"type":"italic"}],"text":"但前提得是隻有 Chrome 一個應用程序在運行"},{"type":"text","text":"。然而,這種情況並不常有,不是嗎?總是會有多個程序同時運行(考慮下系統服務,還有像 Teams 這樣的重量級程序),也就是說,那也許不是最好的主意。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文將探討兩個問題,一是爲什麼最好不要允許應用程序佔用所有的可用內存作爲緩存,二是關於這一問題的可能的解決方案。我將以 Chrome 爲例,因爲它經常成爲抱怨的對象,但本文探討的內容也同樣適用於所有其他的瀏覽器,以及大多數現代化的大型程序。但是,在此之前,讓我們先回顧一些內存管理的基礎知識,以確保我講的和你想的是同一件事。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"內存分頁回顧"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於運行在其上的每個應用程序(進程),現代計算機提供的內存地址空間基本上可以說是無限的。每個進程都認爲只有自己在運行,有海量的內存可供自己使用,從地址 0 到 2^64(在 64 位的機器上)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"顯然,事實並非如此:還沒有計算機有 2^64 物理字節的內存。計算機處理器將物理內存劃分成固定大小的"},{"type":"text","marks":[{"type":"italic"}],"text":"頁幀(page frames)"},{"type":"text","text":"(通常是 4KB),將每個進程的虛擬內存劃分成"},{"type":"text","marks":[{"type":"italic"}],"text":"頁(pages)"},{"type":"text","text":"。然後,操作系統內核負責將虛擬內存頁子集映射到物理頁幀,對於每一次內存訪問,處理器會處理虛擬地址和物理地址之間的轉換。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這種設計下,虛擬地址空間比物理內存要大許多,多個進程(這樣會有多個虛擬地址空間)可以同時運行。換句話說:物理內存被故意"},{"type":"text","marks":[{"type":"italic"}],"text":"過度使用(over-committed)"},{"type":"text","text":"。當一個進程在其虛擬地址空間中分配了較多的內存,可能會沒有足夠的物理內存頁來支撐新分配的虛擬頁。這樣就會導致"},{"type":"text","marks":[{"type":"italic"}],"text":"內存緊張(memory pressure)"},{"type":"text","text":",內核將做些事情來緩解這種情況,嘗試滿足新的內存請求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在內存緊張的情況下,內核會做什麼,這取決於操作系統,但通常來說,內核必須找到已經映射的頁(可以是任何進程的)並把它們驅逐,從而釋放頁幀,爲新的內存請求騰出空間。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以將內存頁分成以下兩類。要了解更多背景信息,我建議你讀下"},{"type":"link","attrs":{"href":"https:\/\/www.usenix.org\/conference\/2000-usenix-annual-technical-conference\/ubc-efficient-unified-io-and-memory-caching","title":null,"type":null},"content":[{"type":"text","text":"NetBSD關於統一緩衝區緩存的論文"}]},{"type":"text","text":":"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"文件頁"},{"type":"text","text":"對應的內存塊直接來自磁盤文件。如果沒有修改的話,這些頁可以隨意丟棄,如果修改了,則可以刷寫到它們的後備文件。例如:用於運行可執行代碼的頁總是可以丟棄,因爲它們是隻讀的,而且磁盤上有後備文件,而通過 "},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#e83e8c","name":"user"}}],"text":"mmap(2)"}]},{"type":"text","text":" 使用的頁可能需要,也可能不需要刷寫到磁盤,這要視它們的髒狀態而定。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"匿名頁"},{"type":"text","text":"對應分配給應用程序的內存塊(考慮下 "},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#e83e8c","name":"user"}}],"text":"malloc"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#e83e8c","name":"user"}}],"text":"new"}]},{"type":"text","text":" )。在內核看來,這些內存的內容是無意義的,因爲它們是由程序邏輯 \"動態 \"填充的,沒有後備資源。這樣一來,如果要驅逐這些頁,就沒有一個文件可供刷寫,所以內核就得把它們放在其他某個地方。那個某個地方就是"},{"type":"text","marks":[{"type":"italic"}],"text":"交換區(swap area)"},{"type":"text","text":"。"}]}]}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"重要提示:關於頁驅逐的一個關鍵細節,也是你閱讀本文接下來的內容時必須留意的一個關鍵細節,就是"},{"type":"text","marks":[{"type":"italic"}],"text":"頁的原始來源不同"},{"type":"text","text":",頁驅逐進程會有所不同。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果系統無法找到足夠的頁來驅逐(例如,已經驅逐了所有文件頁,也已經沒有交換空間來驅逐剩餘的匿名頁),內核就會發生嚴重錯誤,或者開始終止進程,嘗試釋放已使用的內存。在 Linux 上,這是通過備受喜愛的 Out Of Memory killer 機制完成的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至於如何決定從內存中驅逐哪些頁,每個內核都有自己的算法。一般來說,內核會實現一個 LRU 算法驅逐最近最少使用的頁。但是,它也會考慮每次驅逐的“成本”:"}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"成本最低的做法是首先驅逐只讀文件頁,因爲它們不需要通過寫磁盤實現持久化,而且可以快速恢復。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"成本第二低的是驅逐髒文件頁,因爲它們位於文件系統中,可以覆寫。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"成本最高的是驅逐匿名頁,因爲這不可避免地要寫交換區——這反過來又可能會涉及某種空間分配。你永遠不會希望系統到達必須將頁移到交換區的程度,這麼做時,性能就很糟糕了。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不過,這裏就不介紹具體細節了,那和本文接下來的內容沒什麼關係。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"同時運行Chrome和Bazel"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在介紹完背景信息後,讓我們回到最初的討論。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了證明 Chrome 大量使用內存的合理性,通常人們給出的論據是,瀏覽器使用所有內存作爲緩存。持有這種觀點的人認爲,這是好事,因爲人們想要快速的瀏覽體驗,儘量多地緩存數據有助於實現那種體驗。沒錯,不過他們忽略了一個小事實,就是 Chrome 不是在真空中運行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我將採用 Raymond Chen 的分析方法“"},{"type":"link","attrs":{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050607-00\/?p=35413","title":null,"type":null},"content":[{"type":"text","marks":[{"type":"italic"}],"text":"如果兩個程序這樣做會怎麼樣?"}]},{"type":"text","text":"”,說明這爲什麼是個壞主意。飢餓的瀏覽器可能與其他程序同時運行,而其中某些程序也可能是內存密集型的。爲了使示例場景更真實,我們把 Bazel 加入進來,這個應用程序也喜歡佔用大量的內存,以緩存工作空間中數 GB 的構建圖。在這個場景中,我們有一名程序員使用 Chrome 在線研究一些信息,編寫一些代碼(使用某種重量級 IDE),最後使用 Bazel 構建生成的項目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這種情況下,程序員可能首先會密集地使用 Chrome 做些研究。在這個過程中,Chrome 的內存使用可能會逐漸增加,佔用所有可用的內存來緩存頁面和圖片。然後,程序員可能會運行 Bazel 構建項目。而Bazel可能需要額外消耗大量的內存來加載完全依賴圖。但是,此時,Bazel 可能沒有找到足夠的可用內存,所以操作系統將需要換出 Chrome 的緩存內存。這可能會導致後續切回 Chrome 的時候反應速度慢很多,因爲瀏覽器緩存的東西都被換出了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的問題是,像 Chrome 和 Bazel 這樣的應用程序使用匿名內存來運作它們自己的緩存。按定義,緩存內存可以在任意時間隨意丟棄,當出現內存壓力時,內核唯一能看到的是這些應用程序分配了大量的匿名內存。內核並不知道這些頁中是包含必須持久化的寶貴數據,還是可隨意丟棄的易失性數據。由此導致的惡果是,內核可能會決定將緩存數據移到交換區,我前面提到過,一旦用到了交換區,從性能的角度來說,你已經輸了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於這一點,我們有什麼可以做的嗎?"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"協作型內存分配"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你會說,“好吧,我們顯然不能允許應用程序把所有內存都拿來自己用。我們應該限制他們最多使用X%的內存,要留一些內存給其他應用程序使用”。(事實上,這就 Bazel 採用的方案。)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這無法解決任何問題:如果應用程序本身負責查看當前可用的內存,然後獨自決定應該使用多少內存,那麼要麼我們最終還會面臨上面的情況,要麼就是應用程序沒有足夠的內存可以使用。設想一下,如果我們允許 Chrome 使用所有內存的 80%,因爲它知道要留下 20%。然後,Bazel 要運行了,按照配置,它也可以使用可用內存的 80%……是 20% 的 80%,已經很小了。Bazel 受到了巨大的懲罰,只因爲它是第二個運行的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你可以調整這個模型,提出一種有效的方案,但是,通過分佈式決策決定如何使用內存是不夠的。首先,你需要一個能在整個機器上做出明智決策的神使(內核);其次,你不能相信所有的應用程序都會遵守規則。畢竟,那就是幾十年前我們從協作型多任務轉到搶佔式多任務的原因。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"文件緩存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們考慮下這樣一個場景:有很多應用程序,它們幾乎不使用匿名內存,但會大量使用文件系統。這些應用程序每個都會打開許多非常大的文件,對它們執行隨機讀寫操作,而且還打開很長時間。我們同時運行着這些應用程序的多個實例。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這種情況下,我們可能會看到,系統總體的內存使用率接近 100%,和之前一樣,但交換區仍然是空的。更重要的是,雖然系統可能因爲 CPU 和 I\/O 使用率高而變慢,但其性能是可預測的:從命令行執行一條簡單的命令 "},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#e83e8c","name":"user"}}],"text":"ls"}]},{"type":"text","text":" 瞬間就可以完成,不會受內存抖動拖累。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的情況是,內核現在將所有內存作爲其文件緩衝區緩存的一部分;應用程序本身不控制內存。這種內核級的緩存可以跟蹤文件頁(不是匿名頁),通過優化隨機 I\/O 和順序訪問(通過預取)來提升 I\/O 性能。通常,該緩存可以佔用所有可用的內存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與前面介紹的 Chrome 和 Bazel 所採用的方案相比,這種基於文件的方案有一個很大的不同,就是由內核控制一個統一的跨應用程序的緩存,內核對緩存中的內容瞭如指掌。內核可以針對緩存中的內容從整體視角做出決策,儘量保證所有應用程序的正常運行:如果只有一個應用程序在運行,那麼所有的文件緩衝區緩存將都供它使用;但是,如果有兩個或兩個以上的應用程序在運行,那麼它們將“公平地”共享緩存——我這裏之所以加引號,是因爲確實存在相互干擾的問題。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"根本原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼,允許 Chrome 使用所有內存作爲緩存,真正的問題在哪裏?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡單來說,就是操作系統無法查看應用程序的匿名內存,不能自己做決策。由此導致的結果是,當出現內存壓力時,內核唯一能做的事情是,將匿名內存頁推出到磁盤——即使那些頁包含了易失性緩存——後續再從交換區還原它們成本很高。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"有什麼解決方案嗎?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設想一下,如果內核和應用程序之間有一種可以回收內存的反饋機制。內核可以說,“嗨,Chrome,我內存不夠用了,把你不是特別需要的內存釋放出來一些吧”,以此請求回收內存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"遺憾的是,這是不可行的,因爲這得要求所有應用程序配合,在所有情況下都不能做錯。流氓應用程序或是存在缺陷的應用程序會囤積內存,導致更糟糕的情況。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘管如此,Android 就實現了這樣一種方案。Android 的設計就是,系統可以徹底驅逐應用程序的某些部分(活動)。其原理是,系統和應用程序之間有一種協議,通過它可以實現受控的驅逐動作:系統首先會友好地請求應用程序釋放內存,並允許應用程序刷寫數據,但是,即使應用程序沒有按照要求釋放內存,系統也會銷燬那部分內存。這兩種情況都有可能出現,因此,在設計應用程序時必須保證,不管是被優雅地關閉還是強制關閉,它都可以重建狀態——就像它從未退出過。Android 之所以有這樣一種設計,一個原因是它首先是面向移動設備的,這類設備的內存很小,另一個原因是移動設備同一時間主要運行一個應用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一種解決方案是,有一個系統級的緩存服務,可以處理運行應用程序產生的任意內存對象。這樣一個服務可以跨應用程序就內存使用做出協商一致的決策,均勻地刪除緩存條目。但是,和前面的解決方案一樣,需要所有應用程序的配合。否則,一個不合格的應用程序可能會囤積內存,使得其他所有按規則行事的應用程序都受到懲罰。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這就說到了另一種解決方案:劃分內存,預先指定每個程序可以使用的內存大小。容器就是這麼做的,但對於個人計算機來說這並不是一個好方案:硬性劃分無法動態適應用戶的行爲。有時候,你就是隻想瀏覽網頁,在那種情況下,你會希望瀏覽器使用所有可用的資源。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,我們可以嘗試將應用程序都塞進現有系統的設施中。如果應用程序使用文件而不是匿名內存來實現緩存,那麼系統的文件緩衝區緩存就可以正常運行。設想一下,每個應用程序都使用單個的文件來存儲可緩存的對象,而不是使用 "},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#e83e8c","name":"user"}}],"text":"malloc"}]},{"type":"text","text":" 來獲取匿名內存。這時,應用程序會使用打開\/讀取\/關閉循環來訪問那些緩存的對象。在這種情況下,內核中的文件緩存就可以跨應用程序做該做的事:經常使用的緩存條目(文件)會駐留內存,如果內存緊張,就可以把它們驅逐到後備文件中,而且成本很低。性能可能會因爲額外的系統調用而受影響,但總的結果還是要好些。事實上,"},{"type":"link","attrs":{"href":"https:\/\/varnish-cache.org\/docs\/trunk\/phk\/notes.html","title":null,"type":null},"content":[{"type":"text","text":"Varnish就是這樣做的"}]},{"type":"text","text":"!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"遺憾的是,上面所有這些解決方案都需要某種跨程序協同,並且需要所有程序都按規則行事。這在設計新系統時也許可行(就像 Android 所做的那樣),但將這些東西加裝到目前的系統中,肯定是不行的,雖然我希望它可以。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,你可能會認爲,在現如今的世界裏,上面這樣的情況沒什麼問題,因爲計算機有足夠的內存。但它們確實還是問題。我之前在谷歌的時候,就想着要讓人們能夠在 16GB 的筆記本上愉快地使用 Chrome 和 Bazel。每次我的 Surface Go 2 變慢(我一年前新買的機器,但只有 8GB 內存),我就會想起這些問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼,讓我們回到最初的問題:“瀏覽器應該使用所有可用的內存嗎?”不應該,不能像現在這樣做。但是,如果有更好的機制可以實現有效的跨應用程序緩存,答案就是 Yes 了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/jmmv.dev\/2021\/08\/using-all-memory-as-a-cache.html","title":null,"type":null},"content":[{"type":"text","text":"Should the browser use all available memory?"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章