軟體瀏覽器原理:為什麼記憶體管理

computer%20screen%20showing%20data%20visualization...
發表時間:2026 年 10 月 27 日 | 更新日期:2026 年 10 月 27 日 | 編輯:雅寶社區編輯團隊
軟體瀏覽器原理:為什麼記憶體管理 - 雅寶社區 · 頂客論壇

不過,多行程也不是免費的。每個行程都有自己的堆積、自己的 V8 實例、自己的垃圾回收器,光是「重複的執行環境」就會吃掉不少基礎記憶體。這就是為什麼有些人會觀察到:開一個空白分頁,Chrome 可能就吃掉兩三百 MB,而某些輕量瀏覽器只要幾十 MB。這不是 Chrome 特別笨,而是它在為隔離與穩定性付「固定成本」。

為了抵銷這筆成本,現代瀏覽器大量使用跨行程共享記憶體。例如同一份字型檔、同一張被多個分頁引用的圖片、同一段共用程式碼,作業系統層級可以用共享分頁(shared pages)讓多個行程映射到同一塊實體記憶體。這也是為什麼你在工作管理員看到「每個行程各佔 200 MB」,但加總起來的實際實體記憶體用量往往遠低於表面數字——私有記憶體與共享記憶體的計算方式,是評測瀏覽器記憶體時最容易踩坑的地方,後面的評測章節會再詳談。

二、記憶體管理的核心原理:從分配到回收

理解了架構,接著要看機制。瀏覽器的記憶體管理可以粗略拆成三個層次:向作業系統要記憶體(分配)、在程式內部管記憶體(堆積管理與垃圾回收)、以及在資源緊張時做取捨(壓力管理與捨棄)。這三層環環相扣,任何一層設計不良,都會讓使用者感受到「卡」。

虛擬記憶體與分頁:瀏覽器其實在跟作業系統博弈

瀏覽器不會直接拿到實體記憶體,它拿到的是虛擬位址空間。作業系統負責把虛擬頁面映射到實體頁框,並在實體記憶體不夠時,把不常用的頁面換出到磁碟(swap 或壓縮記憶體)。這個機制聽起來很美好,但對瀏覽器來說是一把雙面刃。

好處是:瀏覽器可以「看起來」配置了很大的記憶體,實際上大部分頁面可能從頭到尾都沒被真正觸碰,作業系統自然不會給它實體頁框。這種延遲配置(lazy allocation)讓瀏覽器在啟動時不必真的吃掉大量 RAM。

壞處是:一旦瀏覽器真的開始大量觸碰這些頁面(例如你開了一個超肥的 WebGL 遊戲),作業系統就會被迫把其他程式的頁面換出,整體系統開始抖動。更糟的是,如果作業系統選擇把瀏覽器自己的頁面換出,瀏覽器下次存取時就會發生 page fault,延遲瞬間拉高,使用者感受到的就是「切回分頁時卡一下」。

因此,成熟的瀏覽器不會被動作業系統的被動換頁,而是會主動監控記憶體壓力。以 Chromium 為例,它會透過作業系統提供的記憶體壓力訊號(例如 Linux 的 PSI、macOS 的 memory pressure、Windows 的低記憶體通知)來調整自身行為,包括提早觸發垃圾回收、丟棄快取的解碼圖片、甚至主動捨棄整個分頁。這種「自己先動手,避免被系統殺掉」的策略,是瀏覽器記憶體管理中非常關鍵的一環。

垃圾回收:V8 與 Blink 的雙引擎協作

網頁裡最活躍的記憶體使用者是 JavaScript。V8 引擎採用的是分代式垃圾回收,把物件分成新生代與老生代,用不同策略處理。

新生代(Young Generation)採用的是 Scavenger 演算法,把記憶體切成兩半,存活物件在兩半之間搬移。這個過程又快又頻繁,但只處理「剛出生就死掉」的短期物件——而網頁裡絕大多數物件正是這種短命鬼,所以效果極好。老生代(Old Generation)則是經歷過多次回收仍存活下來的物件,改用標記—清除—壓縮(Mark-Sweep-Compact)策略,成本高得多,因此 V8 會用增量標記、並行標記、甚至利用瀏覽器閒置時間(idle time)來分攤開銷,避免一次停頓太久造成畫面卡頓。

但 JavaScript 不是全部。DOM 節點、CSS 樣式、事件監聽器這些由 Blink 管理的物件,過去是手動管理的,導致大量記憶體洩漏。後來 Blink 引入了 Oilpan 垃圾回收機制,讓 DOM 物件也能被自動追蹤。更複雜的是 JavaScript 與 DOM 之間的跨堆積引用:一個 JS 變數可能握著 DOM 節點的參考,一個 DOM 事件監聽器又可能握著 JS 閉包。如果兩邊的垃圾回收器各管各的,就會出現「A 認為 B 還活著、B 認為 A 還活著」的循環引用,誰都不敢回收。這就是為什麼 V8 與 Blink 必須深度整合、共同遍歷可達性圖,才能正確判定物件生死。

這段聽起來很硬,但對一般使用者的啟示其實很簡單:網頁記憶體洩漏往往不是「忘記 free」這種低級錯誤,而是參考關係沒被正確切斷。例如一個被移除的 DOM 節點仍被某個全域陣列引用、一個已卸載的頁面仍被未清除的 setInterval 回呼綁住、一個被關閉的彈窗仍被事件監聽器拉住。這些東西垃圾回收器不是看不見,而是「看得到但不敢收」。這也是為什麼開發者工具裡的 Heap Snapshot 會是抓漏神器——它能讓你看到「該死的東西為什麼還活著」。

記憶體分配器:被忽略的效能前線

除了垃圾回收,還有一層常被忽略:記憶體分配器。每次 JavaScript 建立物件、每次 Blink 配置版面資料,背後都要向分配器要一塊記憶體。如果分配器設計不良,就會產生碎片、快取不友善、甚至安全漏洞。

Chromium 為此自研了 PartitionAlloc,核心概念是「分區」:把記憶體按用途切成不同區塊(例如專門給 ArrayBuffer、專門給字串、專門給 DOM 物件),這樣不同類型物件的生命週期不會互相干擾,碎片化程度大幅降低,同時也讓攻擊者更難把兩塊不同用途的記憶體排在一起,藉此緩解 use-after-free 這類漏洞的利用難度。這種「安全性與效能一起設計」的思路,是現代瀏覽器記憶體管理的重要趨勢。

三、為什麼瀏覽器特別需要記憶體管理

講到這裡,可能會有人想:一般的桌面程式也需要記憶體管理啊,為什麼獨獨瀏覽器要搞得這麼複雜?答案在於瀏覽器面對的「工作負載」性質,跟一般應用程式有本質上的不同。

網頁是不可信的、不可預測的

一般桌面程式由開發者自己控制,記憶體用多少、什麼時候釋放,大致在掌握之中。瀏覽器卻相反:它每一秒都在載入全世界陌生人寫的程式碼。這些程式碼裡有寫得極爛的、有惡意要吃光你記憶體的、有無窮迴圈的、有把整部影片解碼成幾百張圖片的。瀏覽器不能假設網頁是善意的,也不能假設它是理性的。

因此,瀏覽器的記憶體管理必須同時滿足三個彼此衝突的目標:效能(網頁要跑得快)、隔離(一個網頁不能拖垮其他網頁)、可回收(閒置資源要能被拿回來)。這三個目標的張力,造就了現代瀏覽器一大堆看起來很「龜毛」的設計,例如每個渲染行程有記憶體上限、超過上限就觸發更積極的垃圾回收、再不夠就開始丟棄圖片解碼快取、最後才是整頁捨棄。

分頁捨棄與凍結:資源不夠時的取捨藝術

當系統記憶體吃緊時,瀏覽器會啟動一系列「降級」措施。第一層是丟棄可重建的快取,例如已解碼的圖片、已編譯但暫時用不到的程式碼、預先抓取但還沒用到的資源。這些東西丟掉不會影響功能,只是下次用到時要重新計算或重新下載。

第二層是凍結(freeze)。透過 Page Lifecycle API,瀏覽器可以把背景分頁的計時器、網路請求、動畫全部暫停,只保留必要狀態。這能大幅降低背景分頁的 CPU 與記憶體消耗,而且使用者切回來時可以快速恢復。

第三層才是最激烈的分頁捨棄(discard):把整個分頁的渲染行程終止,只保留網址與標題,等使用者切回來時重新載入。這個動作對記憶體的幫助最大,但代價也最明顯——分頁裡的表單內容、滾動位置、播放進度可能全部消失。這也是為什麼各家瀏覽器對「自動捨棄」的觸發條件都極度保守,通常只在記憶體壓力真的很高、或分頁閒置很久時才會發生。

值得注意的是,「捨棄」與「休眠」是兩種不同策略。前者是殺掉重建,後者是凍結保留。Chrome 的 Memory Saver、Edge 的 Sleeping Tabs、Firefox 的分頁卸載,本質上都在這兩者之間調整。從記憶體管理的角度看,這是一場「保留使用者狀態」與「釋放實體記憶體」之間的持續拉鋸,沒有標準答案,只有取捨。

沙箱隔離的安全代價

還有一個常被忽略的面向:安全隔離本身就是記憶體成本。Site Isolation 這類機制要求不同網站必須跑在不同行程,以阻止 Spectre 這類側通道攻擊竊取跨站資料。但行程越多,重複的執行環境、重複的 V8 堆積、重複的資源快取就越多。換句話說,你換來的安全性,有一部分是用記憶體買的。

這也解釋了為什麼瀏覽器廠商在行動裝置上常常要放寬隔離策略:手機記憶體有限,全部嚴格隔離會讓裝置直接卡死。所以在「隔離強度」與「記憶體可用性」之間,不同平台、不同裝置會有不同的預設值。這是工程妥協,不是偷懶。

四、實測視角:主流瀏覽器的記憶體策略比較

原理講完,回到論壇朋友最感興趣的部分:實際比較。必須先聲明,瀏覽器記憶體評測是出了名的難做,因為影響因素太多——分頁數量、網站類型、擴充功能、作業系統版本、甚至記憶體壓縮設定,都會讓結果差很大。以下比較著重「策略差異」,而非「誰的數字比較低」這種容易誤導的結論。

Chromium 系:隔離優先,成本換穩定

Chrome、Edge、Brave、Opera 等一眾 Chromium 系瀏覽器,共享同一套多行程與 Site Isolation 架構。它的記憶體特徵是「固定成本高、邊際成本相對可控」:開一兩個分頁時看起來很肥,但開到二三十個分頁時,它的共享機制與行程管理反而能讓總量不至於失控。

Chromium 的優勢在於工具鏈成熟。工作管理員可以直接看到每個分頁、每個擴充功能、每個 GPU 緩衝區的記憶體佔用,這種透明度是其他瀏覽器難以比擬的。對於喜歡抓漏、喜歡知道「到底是哪個分頁在吃資源」的使用者,這是很大的加分。此外,PartitionAlloc、Oilpan、跨行程共享字型與資源等機制,也讓它在長期使用下的碎片化程度相對較低。

缺點則是「閒置也要吃記憶體」。因為隔離行程不會因為你沒在看就自動消失(除非觸發捨棄),所以開著一堆分頁不用,Chromium 系的帳面數字通常不會太好看。這也是 Memory Saver 這類功能存在的理由。

Firefox:Fission 之後的平衡路線

Firefox 過去以「比較省記憶體」聞名,但在導入 Fission(站點隔離)之後,這個優勢被部分抵銷了——因為隔離本身就意味著更多行程。不過 Firefox 在排程與記憶體回收上有一些不同的設計取向,例如更積極地在背景分頁上降低資源使用、對影像解碼快取的管理策略不同,讓它在「大量分頁但多數閒置」的情境下,有時能给出比 Chromium 系更漂亮的數字。

Firefox 的另一個特色是對「程序數量」的控制比較保守,不會無限制地為每個網站開新行程,而是會根據記憶體狀況動態調整。這種策略在低記憶體裝置上通常比較友善,但在需要嚴格隔離的高風險情境下,隔離強度可能不如全站隔離來得徹底。這同樣是取捨。

Safari:與作業系統深度綁定的省電派

Safari 在 macOS 與 iOS 上的記憶體策略,最大特色是「與系統壓縮記憶體深度整合」。macOS 有所謂的記憶體壓縮機制,當實體記憶體吃緊時,系統會把不常用的頁面壓縮起來而不是直接寫到磁碟。Safari 的行程模型與這個機制配合得相當緊密,加上它對背景分頁的資源限制向來嚴格,因此在 Mac 筆電上常常給人「比較省電、比較不燙」的印象。

但這種深度綁定也意味著 Safari 的記憶體行為很難用「跨平台通用」的方式評測。它在 macOS 上的表現,跟它在 Windows 上的表現,參考價值完全不同。評測時若不分平台直接比數字,很容易得出誤導性結論。

瀏覽器

行程模型特色

記憶體策略重點

適合情境

Chrome / Edge(Chromium)

嚴格站點隔離,行程數較多

PartitionAlloc、跨行程共享、Memory Saver 捨棄

分頁多、需要透明度與擴充生態

Firefox

Fission 隔離,行程數動態調整

保守開行程、積極凍結背景分頁

中低記憶體裝置、重視開放原始碼

Safari

與 macOS/iOS 行程模型整合

系統壓縮記憶體、嚴格背景限制

Apple 生態、行動裝置省電

評測時最容易犯的三個錯誤

既然談到評測,順手把論壇裡常見的迷思整理一下,避免大家被錯誤數字帶著走。

第一,把「私有記憶體」與「工作集」混為一談。 工作管理員顯示的數字通常是 Working Set,包含共享頁面;而真正代表「這個行程獨佔多少」的是 Private Bytes。兩個數字可能差好幾倍,直接拿來排名沒有意義。

第二,忽略共享記憶體的計算。 多個行程映射同一塊字型或圖片時,每個行程都會「看到」它,但實體記憶體只算一次。如果評測工具沒有去重,加總出來的數字會嚴重高估。

第三,沒有控制變因。 擴充功能是記憶體黑洞,同一個瀏覽器裝十個擴充功能跟裝零個,數字可以差上一倍。廣告阻擋、密碼管理、翻譯套件,每一個都在背景吃資源。不做乾淨設定檔的比較,參考價值極低。

五、回到使用者:從原理出發的實用判斷

講了這麼多架構與機制,最後還是要回答那個最實際的問題:這些原理對我們挑瀏覽器、用瀏覽器有什麼幫助?

「哪個瀏覽器最省記憶體」是個假問題

因為「省記憶體」本身不是目的。真正該問的是:在我的使用情境下,哪個瀏覽器能在可接受的記憶體用量下,給我最好的穩定性與反應速度?

如果你習慣開五十個分頁、又常常切來切去,那麼「捨棄策略保不保守」就比「閒置時吃多少記憶體」重要得多。如果你只在低階文書機上開三五個分頁,那麼「固定成本低」可能才是關鍵。如果你是開發者,需要抓記憶體洩漏,那麼工具鏈的完整度(能否看到每個行程的細節)就遠比帳面數字重要。

換句話說,記憶體管理的評測不該只看「峰值」,而要看「曲線」:長時間使用後會不會持續成長?背景分頁會不會被無預警丟棄?切回分頁時的重建成本高不高?這些才是真正影響體驗的指標。

幾個立即可用的調校方向

如果你讀完原理,想立刻改善手上的瀏覽器體驗,可以從這幾個方向下手:

  • 清理擴充功能。 每一個擴充功能都是一個常駐的執行環境,特別是那些「每個分頁都要注入腳本」的類型,成本會隨分頁數線性成長。定期檢查並移除不用的,效果通常比換瀏覽器更明顯。
  • 善用分頁凍結與休眠。 多數瀏覽器都有「閒置分頁自動休眠」的選項,預設可能是關閉的。打開它,等於把「背景分頁該不該吃資源」的決策交給瀏覽器,通常比手動關分頁更有效率。
  • 不要迷信「記憶體釋放」外掛。 市面上很多號稱「一鍵釋放記憶體」的工具,做的事情往往只是強制觸發垃圾回收或清空快取,短期數字變漂亮,長期反而因為快取消失而讓網頁變慢。瀏覽器自己的壓力管理通常比這些工具聰明。
  • 關注「重建成本」而非只有「佔用量」。 一個被捨棄的分頁切回來要重新載入、重新登入、重新滾到原本位置,這種體驗損失往往比多花兩百 MB 更讓人不爽。這就是為什麼自動捨棄的門檻要設得保守。
  • 善用瀏覽器內建的工作管理員。 不論是 Chrome 的工作管理員、Firefox 的 about:processes、還是 Edge 的瀏覽器工作管理員,都能讓你看到「哪個分頁/哪個擴充功能在吃資源」。這是最直接的抓漏工具,比任何第三方監控都準。
  • 開發者視角:記憶體管理是網頁品質的一部分

    對有在寫網頁的論壇朋友,這段特別值得看。瀏覽器提供了再多記憶體管理機制,也救不了一個從根本上就在洩漏的網頁。常見的洩漏來源包括:未移除的事件監聽器、被全域變數意外捕獲的 DOM 節點、未清除的計時器與訂閱、以及大量建立的物件沒有被正確釋放。這些問題在單一頁面上可能不明顯,但當使用者開著你的網站十幾個小時,就會變成「這個網站越用越卡」的元兇。

    實務上,建議養成幾個習慣:在元件卸載時對稱地清除監聽器與計時器;避免用全域陣列或 Map 無限制地快取 DOM 節點;對於長時間執行的頁面,定期用 Performance Monitor 觀察 JS Heap 與 DOM 節點數是否持續成長;必要時用 Heap Snapshot 比對兩次快照,找出「只增不減」的物件。這些動作不需要很深的記憶體理論,但效果非常直接。

    結語:記憶體管理是瀏覽器的隱形契約

    回到文章開頭的那個問題:為什麼瀏覽器這麼吃記憶體?現在我們應該有能力給出一個比較完整的答案了。因為瀏覽器不是單純的「文件檢視器」,而是一個必須同時承載不可信程式碼、隔離彼此、維持效能、還要與作業系統記憶體壓力共存的微型作業系統。它吃掉的每一塊記憶體,背後大多對應著某種責任:隔離的責任、快取的責任、保留使用者狀態的責任。

    當然,這不是說所有記憶體用量都是合理的。瀏覽器廠商確實有優化空間,網頁開發者也確實常常寫出肥到不行的程式。但理解原理之後,我們至少可以避開兩種極端:一種是看到數字高就喊「肥」,另一種是看到數字低就喊「神」。真正值得關注的,是瀏覽器在壓力下怎麼做取捨、在長時間使用後是否穩定、以及它有沒有把控制權交還給使用者。

    記憶體管理之於瀏覽器,就像煞車之於汽車:平常感覺不到它的存在,但當你需要它的時候,它決定了你是安全停下,還是直接撞牆。下次當你看到工作管理員裡那排瀏覽器行程時,不妨把它們想成一群各自負責、彼此隔離、又在背後偷偷共享資源的小工人。它們看起來很吵、很佔位,但正是這套吵鬧的機制,讓你能安心地在同一個視窗裡,同時開著網銀、論壇、影片和一堆不知道哪裡來的垃圾廣告分頁。

    如果你對這個主題有興趣,歡迎在雅寶社區・頂客論壇的軟體評測版繼續討論。下次我們可以再聊「瀏覽器擴充功能的記憶體成本」或是「如何用開發者工具抓出網頁記憶體洩漏」,這兩個題目都是從今天的原理自然延伸出來的方向。

    ```

    🏠 返回首頁