精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

詳解 JavaScript 各種算法在并行、并發、增量上的優化方案

開發
本文詳細介紹了 JavaScript 中次要垃圾回收的 Scavenger 算法和主要垃圾回收的標記-清除算法的實現細節,以及各種算法在并行、并發、增量上的優化方案,最后介紹了 JS 中垃圾回收的觸發時機。

作者 | xcat

在詳細介紹 JavaScript 的垃圾回收算法之前,我們先來了解下 V8 引擎中的分代布局。

一、分代布局

分代假說(The Generational Hypothesis)認為大多數對象的生命周期非常短暫,即從垃圾回收的視角來看,大多數對象在被分配后幾乎立即變成不可訪問狀態。這一規律不僅適用于 V8 或 JavaScript,對大多數動態語言都成立。

V8 的分代式堆內存布局正是基于這種對象生命周期特征而設計。堆內存被分為「年輕代」(進一步劃分為新生區和中間區兩個子代)和「老年代」。對象首先會被分配在「新生區」。如果它們在下一次垃圾回收中存活,就會被保留在年輕代但晉升為「中間區」狀態。如果它們再次在垃圾回收中存活,就會晉升至老年代。

JavaScript 的垃圾回收算法分為兩種:

  • 次要垃圾回收:使用「Scavenger 算法」,回收年輕代中的垃圾
  • 主要垃圾回收:使用「標記-清除算法」,回收老年代中的垃圾

二、Scavenger 算法

V8 中的次要垃圾回收(Minor GC)正是基于分代假說,使用的是 Scavenger 算法。

它分為「標記」、「轉移」和「指針更新」三個步驟:

  • 標記(marking):找到年輕代中的活躍對象
  • 轉移(evacuating):將標記的對象復制到中間區或老年代(取決于是否已轉移過)
  • 指針更新(pointer-updating):更新被復制對象的所有引用指針

1. 標記

Scavenger 算法的第一步是找到年輕代中的活躍對象。這個類似于標記-清除算法中的標記階段,需要從 GC Roots 開始,遍歷完整個引用圖,才能確定年輕代中哪些是存活的(其他的都是死亡的)。

(1) GC Roots

GC Roots(根集合)是垃圾回收器進行可達性分析的起點,所有從 GC Roots 出發能直接或間接訪問到的對象都被視為存活對象。GC Roots 主要包括以下內容:

①全局對象

  • awindow
  • global

②當前執行上下文中的活動對象

  • 正在執行的函數內部的變量
  • 閉包中引用的外部變量

③DOM 節點

  • 所有未被移除的 DOM 元素的引用

④活動線程和事件隊列中的引用

  • setTimeout、Promise 回調中引用的對象
  • 未解綁的事件監聽器

⑤內置對象和系統引用

  • 當前正在執行的作用域鏈(Scope Chain)
  • 內置對象(如 Math、JSON)的引用

(2) 跨代引用列表

根據分代假說,老年代中的對象大部分都是長期存活的,這意味本來只是為了找出年輕代中的活躍對象,結果卻遍歷了幾乎整個老年代對象。

為了避免遍歷幾乎整個老年代,V8 實現了一個機制,通過寫屏障(Write Barrier)維護了一個「老年代對年輕代的跨代引用列表」(a list of old-to-new references)。然后從 GC Roots 開始遍歷時,遇到老年代對象就直接跳過,僅遍歷其中的年輕代對象,這樣可以找到所有「從 GC Roots 出發,不經過老年代的年輕代」。接著再將跨代引用列表中的對象加入到 GC Roots 中遍歷,同樣是遇到老年代對象就直接跳過,這樣就可以找到所有「被老年代引用的年輕代」。

通過維護了一個「跨代引用列表」的方式,V8 不遍歷老年代就能找到所有年輕代中的存活對象。

(3) 寫屏障

寫屏障是一種在垃圾收集過程中用于保持對象引用完整性和一致性的重要技術。在 V8 引擎中,寫屏障不僅在次要垃圾回收的標記階段用于維護跨代引用列表,也在主要垃圾回收的并發標記和增量標記階段用于更新存活的對象。

寫屏障在 js 執行寫操作(比如 object.field = vaule)的時候會被觸發,若一個對象更新了其引用信息,則會在寫屏障中更新跨代引用列表。保證 Scavenger 算法的標記階段能夠獲得準確的跨代引用信息。寫屏障在并發標記和增量標記的應用將會在后續章節中介紹。

2. 轉移

Scavenger 算法的第二步是將標記的對象復制到中間區或老年代(取決于是否已轉移過一次)。

復制(轉移)是垃圾回收中開銷非常大的操作。不過根據分代假說,年輕代中實際存活的對象比例極低,需要復制的對象也很少。通過僅移動存活對象,其他所有內存都成為了可回收的垃圾。這意味著我們只需承擔與存活對象數量成正比(而非與總分配量成正比)的復制成本。

(1) 半空間

在針對年輕代的回收過程中,存活的對象始終會被轉移到新的內存頁。V8 為年輕代采用了半空間(Semi-Space)設計,這意味著總空間的一半始終預留為空,以支持轉移操作。

在回收期間,初始為空的部分稱為 To-Space,而需要復制的來源區域稱為 From-Space。轉移步驟會將所有存活對象移動到連續的內存塊中(位于同一內存頁內),從而完全消除內存碎片(即死對象留下的間隙)。

隨后會交換兩個半空間的角色——To-Space 變為From-Space,From-Space 變為 To-Space。垃圾回收完成后,新對象的內存分配將從新的 From-Space 的下一個空閑地址開始。

下一次垃圾回收時,From-Space 中剛分配的對象會被轉移到 To-Space,而 From-Space 中已經移動過一次的對象則會被轉移到老年代:

3. 指針更新

Scavenger 算法的最后一步是更新引用地址。注意無論對象是第一次轉移(從 From-Space 到 To-Space),還是第二次轉移(從 From-Space 到老年代),都會在原來的位置留下一個轉發地址,用于更新原始指針的地址。

接下來 V8 需要知道內存中哪些地方引用了這次轉移的對象,更新它們的指針。那么如何找到所有引用了這些對象的對象呢?由于對象的引用是單向的關系,似乎只能重新完全遍歷一次所有內存,才能找到引用了該對象的對象。這肯定是不現實的,它會非常慢。所以 V8 引入了存儲緩沖區,將對象的引用關系由單向變成了雙向的,解決了「如何找到引用了該對象的對象」這個問題。

(1) 存儲緩沖區

V8 在內存中每個對象建立引用關系時,反向記錄了一個地址,指向了引用該對象的對象,使得對象的引用關系就不是單向的了,而是雙向的。這個信息就存儲在「存儲緩沖區」(Store Buffer)中:

如圖所示,Page1 中的對象如果移動了位置,就能通過 Page1 的 Store Buffer 找到引用了 ObjectA 和 ObjectB 的所有對象,然后分別更新其指針即可。但是這樣的結構有個缺點,兩個存儲緩沖區可能包含了同一個指針記錄,當多線程并行執行指針更新時,多個線程可能同時更新同一個指針,造成數據競爭。V8 使用了「記憶集」來解決這個問題。

(2) 記憶集

為了解決多線程并行執行指針更新時的數據競爭問題,V8 使用了「記憶集」(Remembered Set)替代「存儲緩沖區」來記錄對象的引用關系。

因為每個內存頁的大小是固定的,所以可以給 Page2 分配一個固定大小的記憶集,將它「引用的對象的地址的偏移量的位置」標記為紅色:

這樣的話,一旦 Page1 中的對象移動了位置,就可以在每頁的記憶集中尋找固定偏移量的位置,看看是否為紅色,如果為紅色,則說明 Page2 需要更新該引用的指針。多線程可以按頁來分配任務,每個線程更新自己的頁的指針即可,如此一來,再也不會出現多個線程更新同一個頁的指針的情況了。

Scavenger 算法中,標記、轉移、指針更新這三個步驟是交錯進行的,而不是嚴格分階階段完成。具體來說,標記步驟會遍歷 GC Roots,一旦找到活對象,則立即將它轉移到 To-Space(或老年代),然后立即更新它的引用指針,接著再繼續遍歷 GC Roots。這樣交錯執行的好處是可以減少 GC 過程的內存占用,提高復制效率。

4. 并行

并行(Parallel)是將垃圾回收任務分配給多個線程并行執行,但它仍然會阻塞主線程(GC Stop-The-World),只是相對來說阻塞的時間變少了:

并發(Concurrent)則是將任務完全交給其他線程,完全不阻塞主線程:

并行是一種相對簡單的技術,因為主線程的 js 已經暫停了,不會再修改內存。只需要確保多個線程訪問同一個對象時能得到及時的同步。而并發則是比較困難的技術,因為 js 主線程可能隨時讀寫內存,使得垃圾回收中的標記任務變得無效,還需擔心主線程和輔助線程讀寫同一個對象時造成的數據競爭。

次要垃圾回收時,因為只需要掃描年輕代內存,所以標記階段耗時很小。大部分耗時都在轉移階段,而轉移階段是無法并發的——轉移階段肯定不能讓主線程繼續執行 js。次要垃圾回收只能在標記和指針更新階段引入并發,帶來的性能提升很小,反而還增加了寫屏障、線程同步等耗時,得不償失。所以次要垃圾回收只使用了并行技術。

在 v6.2 之前,V8 的次要垃圾回收使用的是一種沒有并行技術的「單線程 Cheney 半空間復制算法」(Single-threaded Cheney’s Semispace Copy)。這種算法其實就是前文中介紹 Scavenger 算法中不包含并行的部分,它簡單易實現,適合單核環境,但也會完全阻塞主線程,沒有利用到多核的性能優勢。

V8 對比了以下這三種算法,最終選擇了如今這種「并行的 Scavenger 算法」:

  • 單線程 Cheney 半空間復制算法
  • 并行標記-轉移算法
  • 并行的 Scavenger 算法

這里我簡單介紹下這三種算法的差異。

(1) 單線程 Cheney 半空間復制算法

這個算法其實就是前文中介紹 Scavenger 算法中不包含并行的部分:

將內存空間分位年輕代和老年代,年輕代分位兩個半空間 From-Space 和 To-Space。垃圾回收器從 GC Roots 開始遍歷,交錯的執行這三個步驟:

  • 標記(marking):找到年輕代中的活躍對象
  • 轉移(evacuating):將標記的對象復制到 To-Space 或老年代(取決于是否已轉移過)
  • 指針更新(pointer-updating):更新被復制對象的所有引用指針

這三個步驟交錯進行,而不是嚴格分階階段完成。

(2) 并行標記-轉移算法

將單線程 Cheney 半空間復制算法改造成多線程的難點在于:

  • 單線程環境下,對引用圖的遍歷是線性的,如果多線程并行遍歷,則容易同時遍歷到同一個對象,造成數據競爭
  • 多線程并行轉移對象時,內存分配容易沖突
  • 指針更新時,另一個線程可能已讀取了未轉移的對象

并行標記-轉移算法(Parallel Mark-Evacuate)為了解決這幾個問題,放棄了單線程 Cheney 半空間復制算法中的交錯執行方式,改為階段性執行:

  • 標記階段:多線程并行執行標記任務,即使重復標記了也沒關系
  • 轉移階段:等所有標記任務全部完成后,再給多線程分配轉移任務,并行轉移到 To-Space 或老年代中。轉移時每個線程都有自己的本地分配緩沖區(local allocation buffers, LABs),轉移完成后會合并到一起
  • 指針更新階段:轉移任務全部完成后,才會多線程并行執行指針更新任務

并行標記-轉移算法使用了分階段執行這種簡單的方式解決了數據競爭、內存分配等問題。但是它沒有考慮到任務的負載均衡問題,部分線程可能任務負載過重,而另一部分線程比較空閑,沒有充分利用到多線程的優勢。

(3) 并行的 Scavenger 算法

V8 最終使用的并行的 Scavenger 算法(Parallel Scavenge)則是更為極致的優化,它維護了一個全局工作列表,多線程首先從多個 GC Roots 出發并行遍歷,每個線程不會遍歷完它的整個圖,而是在遍歷時選擇性的將子節點的遍歷任務加入到全局工作列表中。當單個線程空閑時,就會從全局工作列表「竊取」(stealing)一個任務來處理。

這樣就解決了線程間的負載均衡問題。

另外,并行的 Scavenger 算法中實現了一個屏障(barrier)機制,使得在遍歷時如果遇到一些不適合并行處理的任務時,不會將它放到全局工作列表中(比如線性對象鏈 linear chain of objects)。這個屏障也保證了標記、轉移、指針更新這三個階段可以交錯執行而不會出錯。

通過升級為并行的 Scavenger 算法,次要垃圾回收總時間減少了 55%

5. 增量垃圾回收

增量垃圾回收是一種在瀏覽器空閑時段進行垃圾回收的技術。

(1) 空閑時段

大多數瀏覽器的刷新率是 60Hz,這也是衡量網頁是否卡頓的標準。所以 Chrome 在繪制每一幀之間,有 16.6 毫秒的時間來計算渲染任務。如果 Chrome 在不到 16.6 毫秒的時間內完成了任務,那么在開始渲染下一幀之前,瀏覽器就有空做一些其他時間,這個時間段就稱為空閑時段(Idel period)。瀏覽器提供了一個接口 requestIdleCallback 可以用來注冊空閑任務。

空閑時段只能執行低優先級的任務,包括 js 注冊的空閑任務和空閑垃圾回收任務,空閑任務會有一個截止期限,這是調度器對其預計空閑時間的預估,它的上限是 50ms,以確保瀏覽器能及時響應用戶突然的輸入??臻e任務使用截止期限來估計它可以完成多少工作而不會導致輸入響應卡頓或延遲。

為了在空閑期間執行這些操作,V8 會將垃圾回收的空閑任務提交給調度器。當這些空閑任務運行時,它們會設定一個應該完成的最后期限。V8 的垃圾回收空閑時間管理器會評估應該執行哪些垃圾回收任務,以減少內存消耗,同時遵守最后期限以避免未來在幀渲染或輸入延遲方面的卡頓??臻e垃圾回收任務可能包括次要垃圾回收或主要垃圾回收。

次要垃圾回收的速度很快,如果在空閑時段執行的是次要垃圾回收,則會在這次任務中完成整個次要垃圾回收任務。而主要垃圾回收只會在空閑時段執行增量標記任務。這將在下一章介紹。

三、標記-清除算法

標記-清除(Mark-and-sweep)是垃圾回收中的經典算法。JavaScript 中的主要垃圾回收(Major GC)就是使用這個算法來收集老年代中的垃圾。

它分為「標記」、「清除」兩個主要步驟,以及「壓縮」這一可選步驟:

  • 標記(marking):找到活躍對象
  • 清除(sweeping):回收死內存
  • 壓縮(Compacting)(可選):整理內存碎片

1. 標記階段

標記階段用來確定哪些對象可以被回收,它是垃圾回收的核心環節。

垃圾回收器通過「可達性」來判斷對象的「存活狀態」。這意味著當前運行時環境中所有可達的對象必須保留,而不可達的對象則需要被回收。標記過程即尋找可達對象的過程。垃圾回收器從一組已知的指針起點(稱為 GC Roots)開始遍歷,沿著每個指向 JavaScript 對象的指針進行追蹤,將找到的對象標記為可達。回收器會遞歸地追蹤這些對象內部的所有指針,直到標記出運行時環境中所有可達對象。

(1) 并發標記

并行(Parallel)是將垃圾回收任務分配給多個線程并行執行,但它仍然會阻塞主線程,只是阻塞的時間變少了:

并發(Concurrent)則是將任務完全交給其他線程,完全不阻塞主線程:

并行是一種相對簡單的技術,因為主線程的 js 已經暫停了,不會再修改內存。只需要確保多個線程訪問同一個對象時能得到及時的同步。而并發則是比較困難的技術,因為 js 主線程可能隨時讀寫內存,使得垃圾回收中的標記任務變得無效,還需擔心主線程和輔助線程讀寫同一個對象時造成的數據競爭。

次要垃圾回收時,因為只需要掃描年輕代內存,所以標記階段耗時很小。大部分耗時都在轉移階段,而轉移階段是無法并發的。所以次要垃圾回收只使用了并行技術。引入并發只能減少標記和指針更新階段耗時,反而增加了寫屏障、線程同步等耗時,得不償失。

主要垃圾回收時,因為需要掃描整個老年代內存,所以標記階段耗時比較長。所以主要垃圾回收可以利用并發標記技術,使得 V8 的標記階段都在輔助線程中執行時,完全不阻塞 js 主線程:

(2) 三色標記

標記階段的工作可以看作是圖的遍歷。堆內存上的對象就是圖的節點,一個對象對另一個對象的指針就是圖的邊。標記階段的目標就是從 Roots 出發,找到所有引用到的對象。

假如是單線程遍歷圖,可以在一個調用棧中直接廣度或深度遍歷即可。但要實現多線程并發標記,則需要有一個標記工作列表(marking worklist),每個線程都從標記工作列表中拿取一個工作,并且把下一層級的工作推入到標記工作列表中。

V8 在標記階段會將每個節點標記為三種顏色:

  • 白色:尚未發現的節點
  • 灰色:發現白色節點,將其推入到標記工作列表中,變成灰色節點
  • 黑色:從標記工作列表中拿取一個灰色節點,訪問其所有字段,這些字段中若有白色節點則推入到標記工作列表中變成灰色節點,訪問完所有字段后,將該節點變成黑色

當標記工作列表為空時,就意味著完成了整個標記階段,確定了圖中所有的活躍對象(黑色節點)和死亡對象(白色節點)。

(3) 寫屏障

并發標記時,主線程還在執行 js:

此時主線程可能修改內存中的引用關系,多線程的讀寫操作造成了數據競爭,這導致輔助線程中的三色標記失效。

寫屏障解決了數據競爭的問題。寫屏障在 js 執行寫操作(比如 object.field = vaule)的時候會被觸發,若一個字段從一個對象指向一個新的對象時,寫屏障會檢查并調整新對象的顏色(標記狀態),如果該對象是白色(未被標記為活的),將其改為灰色并加入待處理隊列。

寫屏障會帶來一定的性能開銷,但它確保了三色標記的正確性。

(4) 并行標記

大部分情況下,并發標記不阻塞主線程,是更優的選擇。

但有時候,對象的引用關系可能涉及復雜的線程同步問題,使得標記工作難以并發執行。

此時輔助線程會將此標記工作任務推送到一個名為救援工作列表(Bailout worklist)的列表中,求助于主線程通過阻塞 js 來執行此標記任務。

救援工作列表中的任務只會被主線程取走,此時會阻塞主線程的 js 執行,所有線程都會并行的執行標記任務:

(5) 增量標記

瀏覽器在下一幀渲染之前,可能有一些空閑時段,這個時段也可以用來做主要垃圾回收的增量標記任務。

為了減少對應用程序性能的影響,增量標記任務可以在多個空閑時段中執行,每個空閑時段內執行一段時間,然后中斷以便其他重要任務(如主線程的 JavaScript 任務)可以繼續執行。在下一個空閑時段,再繼續未完成的標記任務。

在增量標記過程中,垃圾回收并非一次性完成,而是分成許多小的步驟。在主線程 js 執行過程中,內存中對象的引用關系可能發生變化,這會導致之前的標記失效了。為了解決這個問題,V8 使用寫屏障來標記那些引用關系發生變化的對象。這樣,即便在垃圾回收暫停期間對象的引用關系發生了變化,垃圾回收器依然能夠準確地識別和處理這些變化。

由于清除任務和壓縮任務的耗時較長,空閑時段不會用來做清除任務和壓縮任務。

(6) 黑色分配

根據分代假說,大多數對象的生命周期非常短暫,在次要垃圾回收中就會被回收掉。而經歷了兩次次要垃圾回收都沒被回收的對象,就會被晉升到老年代。

我們可以認為,剛從新生代晉升到老年代的對象,大概率是一個長期活躍的對象,至少在下次主要垃圾回收時也還是活躍的對象,不會被回收——假如一個剛晉升到老年代的對象馬上就被回收了,說明這個分代假說本身就有問題了。既然它大概率在下次主要垃圾回收時還保持活躍,那么就沒必要在標記階段掃描它了,直接將它標記為活躍即可。這就是黑色分配的理論依據——剛晉升到老年代的對象,至少應該在下一次主要垃圾回收中存活下來。

在次要垃圾回收的標記階段,V8 將準備從新生代晉升到老年代的對象染成黑色。在次要垃圾回收的轉移階段,黑色對象會被移動到一個特殊的黑色內存頁中,這個內存頁的所有對象都是黑色的。在下次主要垃圾回收的標記階段,將會直接跳過黑色內存頁的掃描。

黑色分配這一優化手段將吞吐量和延遲得分提高了約 30%,同時由于標記進度更快且整體垃圾收集工作更少,內存使用量減少了約 20%。

2. 清除階段

清除過程會將死亡對象留下的內存空隙加入名為「空閑列表(free-list)」的數據結構。當標記完成后,垃圾回收器會掃描整個堆內存,找到由不可達對象形成的連續內存空隙,并將其加入對應大小的空閑列表??臻e列表按內存塊大小分類存儲以便快速檢索。后續需要分配內存時,只需查詢空閑列表即可找到合適大小的內存塊。

(1) 并發清除

因為待清除的內存都是死亡內存,絕對不會再被主線程訪問到了。所以清除任務可以完全放在輔助線程中并發執行。并且即使主線程 js 已經恢復執行時,輔助線程的清除任務還可以繼續執行。

3. 壓縮階段

基于碎片化啟發式算法(fragmentation heuristic),主要垃圾回收會選擇性地對某些內存頁執行對象遷移/壓縮操作。

這個過程可以類比老式電腦的硬盤碎片整理:我們將存活對象復制到當前未被壓縮的其他內存頁(利用其空閑列表)。通過這種方式,可以充分利用死亡對象遺留在內存中的零散小空隙。復制存活對象存在一個潛在問題:復制大量長生命周期對象會帶來高昂成本。因此我們選擇只壓縮碎片化程度較高的內存頁,而對其他內存頁僅執行清除操作(不復制存活對象)。壓縮階段會阻塞 js 主線程,避免數據競爭帶來的問題。壓縮階段會并行執行。

最后總結一下,標記-清除算法的整個流程如下:

(1) 并發、增量標記:當堆內存接近動態計算的上限時,V8 會啟動并發、增量標記。瀏覽器會在主線程空閑階段執行增量標記,在非空閑階段執行并發標記。主線程執行期間可能會產生新的對象引用關系,V8 采用寫屏障(Write Barrier)機制來記錄 js 在并發、增量標記階段創建的新對象引用,確保標記結果的準確性,當遇到難以并發執行的標記任務時,會推入到救援工作列表中,交給最終標記階段執行。

(2) 最終標記(并行標記):并發、增量標記完成后,主線程會暫停執行 js,此時進入最終標記階段(marking finalization),多線程并行執行救援工作列表的工作,然后重新掃描 GC Roots,確保所有存活對象都被標記了。

(3) 并行壓縮階段:主線程繼續暫停執行 js,多線程并行執行壓縮任務,將存活對象移動到連續內存塊以減少碎片,并更新相關指針。部分無法壓縮的頁則通過空閑列表(free-list)進行內存回收。

(4) 并發清除階段:與此同時,輔助線程執行并發清除任務,這些任務與并行壓縮及主線程代碼執行同時進行,即使主線程 js 恢復運行,清除任務仍可在輔助線程中繼續執行。

四、垃圾回收的觸發時機

JavaScirpt 的垃圾回收時機無法用程序控制,這是設計如此的:

  • 程序員可能希望在時間關鍵的應用階段關閉垃圾回收,以避免因垃圾回收引起的幀丟失。然而,這會使應用邏輯變得復雜,維護變得困難。如果在代碼的某個分支中忘記重新開啟垃圾回收,可能會導致內存耗盡。
  • 程序員無法預估手動觸發的垃圾回收需要多長時間,可能會導致應用程序本身引入卡頓,反而無法達到預期的性能優化效果。
  • 這會給 js 引擎帶來額外的工作,手動觸發垃圾回收可能會干擾垃圾回收器的啟發式算法,導致不可靠的內存管理行為。

1. 次要垃圾回收

  • 當年輕代的活動空間被填滿時觸發
  • 當程序請求分配新的內存,并且年輕代沒有足夠內存時觸發
  • 當空閑時段有足夠的空閑時間時觸發。但并不是一定會觸發,因為頻繁的觸發可能導致本可以在次要垃圾回收中得到回收的對象被移入了老年代

2. 主要垃圾回收

  • 當老年代中的對象占用空間增長到超過某個啟發式計算的內存限制時觸發
  • 如果整個堆的使用情況超過了特定的內存閾值,基于啟發式算法,系統可能觸發主要垃圾回收
  • 當堆大小達到某個策略設定的開始增量標記的限制時,會開始在空閑時段執行增量標記,增量標記完成后,開始清除和壓縮,最終完成主要垃圾回收
  • 在檢測到應用的長期不活躍狀態時,甚至在沒有達到內存限制的情況下,可能主動進行主要垃圾回收來減少內存占用

3. 動態的垃圾回收頻率

在一次完整的垃圾收集結束時,V8 的堆增長策略會根據存活對象的數量和內存的余量,來決定下一次垃圾收集的時間。所以垃圾回收的頻率會根據內存的狀態實時變化。

4. 低內存模式

垃圾回收的吞吐量、造成的頁面延遲以及占用內存之間是一個不可能三角。針對不同的設備,需要有不同的內存回收策略。對于內存較低的移動設備,即內存少于 512 MB 的設備,優先考慮延遲和吞吐量而不是內存消耗可能會導致內存不足而崩潰。

為了更好地平衡這些低內存移動設備的權衡,V8 引入了一種特殊的低內存模式,該模式調整了一些垃圾收集啟發模式以降低 JavaScript 垃圾收集堆的內存使用量。一般來說,在一次完整的垃圾收集結束時,V8 會根據存活對象的數量和內存余量來決定下一次垃圾收集的時間。在低內存模式下,內存余量更少,所以垃圾回收會更頻繁的觸發。

一般來說,主要垃圾回收會在內存還有空余時觸發,此時會在空閑時段執行增量標記,等標記任務完全完成后,才會阻塞主線程,開始執行清除和壓縮。但在低內存模式下,由于內存余量更少,可能在增量標記還未完成時,就觸發了主線程的垃圾回收,此時主線程 js 阻塞,主線程和輔助線程并行的執行剩余的標記任務和后續的清除、壓縮任務。低內存模式雖然使垃圾回收更頻繁了,但是也使得移動端設備上的堆內存消耗減少了 50%

5. 不活躍的網頁

一般來說,瀏覽器會對每個網頁限制內存,一旦達到限值,則會啟動主要垃圾回收。然而,如果網頁在達到分配限制之前變得不活躍,那么在網頁整個不活躍期間都不會進行主要的垃圾回收——這正是大多數網頁會遇到的情況——大多數網頁在加載頁面時會使用較多內存,因為它們正在初始化其內部數據結構,加載后不久(幾秒或幾分鐘內),網頁通常變得不活躍。如果此時還未達到內存限值,就不會進行主要垃圾回收了。

這會導致不活躍的網頁遲遲得不到內存回收。所以 Chrome 實現了一個名為「Memory Reducer」的控制器,它會檢測網頁何時變得不活躍,并主動調度一次主要垃圾回收——即使此時還未達到內存分配限制。

責任編輯:趙寧寧 來源: 騰訊技術工程
相關推薦

2015-11-10 09:34:58

JavaScript方式

2023-07-10 16:18:18

性能優化開發

2009-10-26 16:38:16

接入網方案

2010-05-07 11:00:25

Oracle多表查詢

2016-08-04 13:19:06

MySQL數據庫大優化

2017-11-22 14:20:07

前端JavaScript排序算法

2014-10-09 09:48:14

JavaScript

2016-08-12 11:04:17

JavaScript物聯網應用

2021-09-18 09:53:48

京東客服IM消息消息處理

2017-03-17 14:18:34

JavaScript算法問題詳解

2010-04-07 16:41:50

Oracle SQL優

2010-03-29 10:55:38

Oracle優化

2009-06-03 15:27:07

CPU網絡優化網康

2019-11-11 15:10:37

FedoraLinuxbash

2011-05-19 09:10:17

JavaScriptLinux

2009-08-04 14:48:26

并發和并行的區別

2017-03-03 16:50:01

2025-03-31 10:42:31

2023-10-07 08:54:28

項目httpPost對象

2015-08-26 10:13:55

排序算法總結
點贊
收藏

51CTO技術棧公眾號

国产三区在线视频| 国产手机精品在线| 九一在线免费观看| 国产亚洲久久| 亚洲国产精品尤物yw在线观看| 久久久久久久爱| 熟妇人妻久久中文字幕| 欧美aaa大片视频一二区| 亚洲少妇屁股交4| 精品免费一区二区三区蜜桃| 一区二区三区麻豆| 国产一区日韩一区| 在线播放国产精品| 欧美双性人妖o0| 福利一区在线| 天天综合色天天综合色h| 欧美三级网色| 亚洲精品一区二区口爆| 日韩精品成人一区二区三区| 欧美成人免费小视频| 手机免费看av| 老汉色老汉首页av亚洲| 欧美裸体bbwbbwbbw| 日韩精品―中文字幕| 婷婷视频在线| 91蜜桃在线观看| 3d蒂法精品啪啪一区二区免费| 亚洲av无一区二区三区| 国产三级精品三级在线观看国产| 国产欧美一区二区三区鸳鸯浴| 少妇激情综合网| av无码一区二区三区| 日韩毛片免费看| 色一区在线观看| 分分操这里只有精品| 成人日批视频| 亚洲同性gay激情无套| 欧美午夜精品久久久久久蜜| 亚洲精品视频网| 国产真实乱偷精品视频免| 琪琪第一精品导航| 日韩特黄一级片| 欧美日韩国产一区精品一区| 日韩在线观看免费全| 国产成人一区二区在线观看| 亚洲肉体裸体xxxx137| 亚洲成av人影院在线观看| 久久精品亚洲天堂| 9999在线精品视频| 欧美日韩aaaaaa| 亚洲 激情 在线| 开心久久婷婷综合中文字幕| 91成人在线免费观看| 一女被多男玩喷潮视频| 99riav视频在线观看| 亚洲一区二区在线免费看| 性生活免费观看视频| а√天堂官网中文在线| 亚洲男女一区二区三区| 91精品国产吴梦梦| 在线网址91| 亚洲一区在线看| 日韩精品综合在线| gogo久久| 欧美色videos| 人妻丰满熟妇av无码区app| 成人影院网站| 在线精品视频免费观看| 99re精彩视频| 国产日韩在线观看视频| 日韩一区二区三区视频| 亚洲成人福利视频| 美女一区2区| 亚洲乱码av中文一区二区| www.中文字幕av| 日韩夫妻性生活xx| 不卡av日日日| 国产精品7777777| 老司机精品视频网站| 国产精品女视频| 97免费观看视频| 国产91精品一区二区麻豆亚洲| 国产成人精品av在线| 波多野结衣视频免费观看| 六月丁香婷婷久久| 成人免费视频在线观看超级碰| 日本视频在线观看免费| 日本女优在线视频一区二区| 亚洲aaa激情| 污视频软件在线观看| 亚洲国产高清aⅴ视频| 中文字幕在线中文| 欧美专区福利免费| 69堂国产成人免费视频| 日韩免费高清一区二区| 三级电影一区| 久久久久久久久久久免费精品| 日本一二三区在线观看| 亚洲第一黄色| 国产日韩欧美黄色| 天天色综合av| 成人欧美一区二区三区小说| 久色视频在线播放| 疯狂欧洲av久久成人av电影| 日韩av在线最新| 日本精品在线免费观看| 国产色综合网| 亚洲自拍欧美色图| 国产福利片在线| 亚洲国产精品欧美一二99| 亚洲 欧美 日韩系列| 爱高潮www亚洲精品| 在线播放国产一区二区三区| 国产在线欧美在线| 美女性感视频久久| 久久99精品久久久久久水蜜桃| 少妇av在线播放| 国产精品激情偷乱一区二区∴| 亚洲精品一区二区三区樱花| av成人影院在线| 91精品国产手机| b站大片免费直播| 在线精品一区| 99电影在线观看| 日本在线观看免费| 色哟哟欧美精品| 你懂的在线观看网站| 亚洲情侣在线| 国产精品高潮粉嫩av| 日本波多野结衣在线| ...av二区三区久久精品| 久章草在线视频| 色婷婷av一区二区三区丝袜美腿| 日韩国产精品视频| 久久久久成人片免费观看蜜芽| 一区在线观看| 99电影网电视剧在线观看| 黄网页免费在线观看| 91国偷自产一区二区开放时间| 亚洲一级片免费| 精品高清在线| 国产精品福利无圣光在线一区| 美国一级片在线观看| 日日夜夜一区二区| 茄子视频成人在线观看| 成人欧美magnet| 亚洲精品自拍第一页| 日韩av电影网| gogo大胆日本视频一区| 97视频在线免费| caoporn成人| 欧美成人精品三级在线观看| 97人妻精品一区二区三区软件| 成人综合在线视频| 国产精品一二三在线观看| 免费欧美网站| 欧美激情视频网址| 亚洲乱码精品久久久久.. | 九九九九九国产| 成人看的羞羞网站| 成人妇女免费播放久久久| 黄色片网站在线| 日韩欧美亚洲一区二区| 国产无码精品在线观看| 91色.com| 午夜两性免费视频| 一区二区中文| 国产精品区一区二区三在线播放| 日本国产在线| 欧美影院一区二区| www欧美com| 国产精品一品视频| 国产黄页在线观看| 日本一区二区在线看| 亚洲www视频| 国产夫妻在线播放| 日韩精品中文字幕久久臀| 蜜臀99久久精品久久久久小说| 丁香亚洲综合激情啪啪综合| 亚洲国产成人精品无码区99| 亚洲美女久久| 91在线观看免费高清| 久操av在线| 亚洲色图美腿丝袜| 国产精品伦理一区| 欧美日韩午夜激情| 蜜桃视频最新网址| 91亚洲精品乱码久久久久久蜜桃| 欧美日韩中文字幕在线播放| 国产成人精品亚洲线观看| 欧美亚洲成人xxx| 91免费在线| 亚洲成人精品在线| 最近中文字幕在线观看| 亚洲国产成人高清精品| 日韩欧美黄色网址| 成人午夜私人影院| 国产三级国产精品国产专区50| 精品产国自在拍| 91久久精品视频| 东京一区二区| 欧美激情a在线| av在线首页| 日韩av一区在线观看| 国产尤物视频在线观看| 欧美视频中文在线看| 国产女人18水真多毛片18精品| 国产一区二区女| 免费成人在线视频网站| 影音先锋成人在线电影| 日本免费高清不卡| 久久精品色综合| 91视频99| 亚洲欧洲专区| 国产精品精品国产| 日本在线影院| 欧美风情在线观看| 日本高清中文字幕在线| 精品丝袜一区二区三区| www.蜜臀av.com| 欧美日韩久久不卡| 麻豆精品久久久久久久99蜜桃| 久久亚洲精品国产精品紫薇| 2025中文字幕| 国产真实乱对白精彩久久| 欧洲熟妇精品视频| 亚洲综合丁香| 亚洲熟妇无码一区二区三区导航| 天堂综合网久久| 国产成人精品免费视频大全最热 | 天堂在线精品| 国产私拍一区| 国产成人夜色高潮福利影视| 91成人免费看| 亚洲成人黄色| 91久久极品少妇xxxxⅹ软件 | 一二三区视频在线观看| 久久精品av麻豆的观看方式| 成人黄色片视频| 久久国产免费| 白嫩少妇丰满一区二区| 久久精品30| 国产女女做受ⅹxx高潮| 久久久夜夜夜| 日韩有码免费视频| 三级久久三级久久| 最新天堂中文在线| 久久精品国产久精国产爱| jizz大全欧美jizzcom| 日韩国产一区二| 色婷婷一区二区三区av免费看| 亚洲午夜视频| 欧美男女爱爱视频| 国产欧美午夜| 国产成人精品无码播放| 亚洲人成人一区二区三区| 黄色一级视频在线播放| 国产一级久久| 91激情视频在线| 蜜臀av一区二区| 日本中文字幕在线不卡| 国产成人精品综合在线观看| 逼特逼视频在线观看| 不卡一区二区三区四区| 91久久免费视频| 中文成人综合网| 999精品在线视频| 一个色妞综合视频在线观看| 日本一区二区免费在线观看| 亚洲v日本v欧美v久久精品| 国产精品国产三级国产专区52 | 国产午夜视频在线| 亚洲aaa精品| 亚洲婷婷久久综合| 欧美一级在线免费| 手机看片一区二区三区| 一区二区欧美在线| 2021国产在线| 国产91成人video| 日本免费一区二区三区等视频| 68精品国产免费久久久久久婷婷| 欧美jizzhd欧美| 欧美激情欧美激情在线五月| 裤袜国产欧美精品一区| 成人av在线网址| 麻豆一区二区麻豆免费观看| 亚洲精品一区二区三| 综合五月婷婷| 欧美成人精品欧美一级乱| 国产在线精品免费| 久久久久久久久免费看无码| 中文字幕一区三区| 国产又大又黄又粗| 在线成人av影院| 日韩a在线看| 久久99青青精品免费观看| 亚洲三级欧美| 岛国一区二区三区高清视频| 国产一区2区| 国产3p露脸普通话对白| 老汉av免费一区二区三区| 男人网站在线观看| 国产精品的网站| 亚洲免费黄色网址| 日韩精品在线一区二区| 国产视频第一页在线观看| 久久久久久久久久久91| 欧美成人一二区| 欧美日韩国产综合视频在线| 欧美在线高清| 国产又黄又猛的视频| 久久久久久99久久久精品网站| 国产精品天天干| 婷婷丁香激情综合| 亚洲av少妇一区二区在线观看| 日韩欧美一级精品久久| 91最新在线| 国产成人a亚洲精品| 欧美顶级毛片在线播放| 粉嫩av一区二区三区天美传媒 | 欧美成年人视频| 波多野结依一区| 97久久人人超碰caoprom欧美| 精品视频在线播放一区二区三区 | www.我爱av| 日韩中文字幕在线看| 成人激情综合| 欧美大香线蕉线伊人久久| 国产精品第十页| 91香蕉视频免费看| 亚洲色图视频免费播放| 夜夜爽8888| 中文字幕久久亚洲| 久久天堂av| 色噜噜色狠狠狠狠狠综合色一| 四虎成人av| 自拍偷拍 国产| 亚洲国产精品成人久久综合一区| 国模无码国产精品视频| 欧美精选一区二区| 精品孕妇一区二区三区| 国产在线一区二区三区| 日韩伦理视频| 亚洲免费av一区| 中文字幕一区日韩精品欧美| 91欧美日韩麻豆精品| 中文字幕亚洲激情| 成人精品视频在线观看| 青青草免费在线视频观看| 国产成人一级电影| 国产一级做a爰片在线看免费| 欧美性三三影院| bbbbbbbbbbb在线视频| 国产精品久久久久久久久免费看| 日韩欧洲国产| 日韩在线观看a| 91视频观看视频| 日本久久综合网| 色噜噜狠狠狠综合曰曰曰| 国产情侣一区二区三区| 亚洲国产精品影视| 国产成a人无v码亚洲福利| 国产性猛交普通话对白| 亚洲黄色片网站| 久久久人成影片一区二区三区在哪下载 | 秋霞成人午夜伦在线观看| 欧美一区二区三区粗大| 欧美日韩黄色影视| 91在线中文| 蜜桃av噜噜一区二区三区| 日本欧美加勒比视频| 欧美黑人猛猛猛| 日韩高清av一区二区三区| 成人h在线观看| 嫩草影院中文字幕| 26uuu精品一区二区三区四区在线| 久久国产在线视频| 亚洲另类激情图| 欧美亚洲人成在线| 日韩精品一区在线视频| 久久久久久久久一| 999免费视频| 日韩av免费网站| 中出一区二区| 好吊视频在线观看| 51精品视频一区二区三区| 国产高潮在线| 一区二区三区四区视频在线| 国产99久久久国产精品| 亚洲黄网在线观看| 欧美成在线视频| av中文一区| 亚洲乱妇老熟女爽到高潮的片| 亚洲美女淫视频| 日本中文字幕电影在线观看| 成人午夜激情免费视频| 国产精品一页| 欧美成人精品一区二区免费看片 | 日韩中文在线电影| 在线视频 日韩|