91网首页-91网页版-91网在线观看-91网站免费观看-91网站永久视频-91网站在线播放

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

V8 引擎是如何給 JS"打掃房間"的 ?

freeflydom
2025年7月10日 9:53 本文熱度 71

JS 語言不像 C/C++, 讓程序員自己去開辟或者釋放內存,而是類似Java,采用自己的一套垃圾回收算法進行自動的內存管理。今天就從內存結構說起,一步步聊聊 V8 的垃圾回收機制。

先搞懂JS 的內存都存在哪里?

JS 的內存存儲分兩塊:棧(Stack)  和堆(Heap) ,就像家里的 "鞋柜" 和 "儲物間"—— 常用的小東西放鞋柜,大件雜物放儲物間。

棧是一塊連續的內存空間,就像排隊的抽屜,每個抽屜大小固定。它主要存兩種東西:

  • 基本類型值(Number、String、Boolean 等),比如let age = 25age和 25 都存在棧里;
  • 引用類型的地址(指針),比如let user = {name: '張三'},user這個變量名存在棧里,而{name: '張三'}這個對象存在堆里,棧里的user只存了指向堆中對象的地址。
  • 閉包是存儲在堆內存中的

棧的回收特別簡單:函數執行時會創建 "執行上下文",壓入棧頂;函數執行完,執行上下文彈出,棧頂的內存會被自動回收。這個過程由 JS 引擎自動完成,靠的是ESP 指針(棧指針)的移動:函數執行時 ESP 上移,執行完 ESP 下移,原來的棧空間就成了 "可回收區域"。

堆是一塊不連續的內存空間,大小不固定,就像開放式儲物間,專門存引用類型(對象、數組、函數等)。比如創建一個{name: '張三', age: 25}對象,它的鍵值對全存在堆里;數組[1, 2, 3]的元素也存在堆里。

堆的麻煩在于:對象不會像棧里的變量那樣 "用完就走"。比如全局對象window.appData = { ... },只要頁面不刷新,它就一直占著堆內存;再比如閉包中被引用的對象,即使函數執行完,只要還被引用,就不會被回收。這些不再被引用的對象,就是堆里的 "垃圾"—— 如果不及時清理,堆內存會被越占越多,最終導致頁面卡頓甚至崩潰。

V8 的內存結構

V8 引擎把堆內存又細分了兩塊:

  • 新生代內存:臨時貨架,存存活時間短的對象(比如函數里的局部對象、循環中創建的臨時變量)。64 位系統下約 32MB,32 位系統約 16MB,空間不大但回收頻繁。
  • 老生代內存:長期儲物柜,存存活時間長的對象(比如全局變量、被多次回收仍存在的對象)。64 位系統下最大約 1.4GB,32 位系統約 0.7GB,空間大但回收頻率低。

這就是 V8 的 "分代回收" 思路:不同生命周期的對象,用不同的方式回收,效率更高。

棧內存的回收

棧的回收幾乎不用我們操心,全靠 JS 引擎的 "執行上下文管理"。舉個例子:

function add(a, b) {
  let sum = a + b; // sum存在棧里
  return sum;
}
let result = add(1, 2); // add執行時,上下文入棧;執行完,上下文出棧
  • 調用add(1, 2)時,JS 引擎會創建一個執行上下文,壓入棧頂,里面包含a=1、b=2sum=3這些變量。
  • 函數返回后,執行上下文從棧頂彈出,ESP 指針下移到上一個上下文(全局上下文)。此時a、b、sum占用的??臻g就成了 "無效區域",下次有新函數調用時,直接覆蓋這些空間就行 —— 不用專門 "清理",相當于自動回收。

這種回收方式效率極高,幾乎不消耗額外性能,所以棧內存很少出問題。

新生代內存的回收

新生代存的都是 "短命對象",比如循環里創建的臨時對象:

for (let i = 0; i < 1000; i++) {
  const temp = { id: i }; // 每次循環創建的temp對象,用完就成垃圾
  console.log(temp.id);
}

這些對象的回收,V8 用的是Scavenge 算法,核心是 "復制存活對象,清空剩余空間"。具體步驟可以腦補成這樣:

  1. 新生代內存被分成兩塊等大的空間,一塊叫 "From 空間"(正在用),一塊叫 "To 空間"(閑置),就像兩個并排的抽屜,每次只用一個。

  1. 當 From 空間快滿時,觸發回收:遍歷 From 空間,把所有還在被引用的 "存活對象",按順序復制到 To 空間。
  2. 復制完后,直接清空 From 空間(把舊抽屜里的垃圾全扔了),然后交換 From 和 To 的角色 —— 下次用新的 From(原來的 To),閑置新的 To(原來的 From)。

為什么要這么折騰?主要是為了避免 "內存碎片"。如果直接刪除垃圾,存活對象可能零散分布在內存中,就像抽屜里的雜物東一個西一個,下次想放個大點的對象(比如一個長數組),可能找不到連續的空間。

而復制到 To 空間時按順序排列,存活對象會擠在一起,剩下的空間是一整塊連續區域,下次分配新對象就很方便。

當然,這種方式也有代價:新生代內存實際只能用一半(總有一個空間閑置)。但好在新生代對象存活時間短,復制成本低,總體算下來比標記清除快得多。

老生代內存的回收

當新生代的對象 "活過" 多次回收(比如被全局變量引用,或者在閉包里被長期持有),就會被 "晉升" 到老生代。 晉升的條件有兩個

  • 已經經歷過一次 Scavenge 回收。
  • To(閑置)空間的內存占用超過25%。

老生代的對象要么體積大,要么存活久,用 Scavenge 算法復制太費時間,所以 V8 換了套思路:標記 - 清除+標記 - 整理。

第一步:標記 - 清除

  1. 標記階段:從全局對象(比如window)開始,遍歷所有能訪問到的對象,給它們貼個 "有用" 的標簽(可達性分析)。
  2. 清除階段:遍歷完后,沒貼標簽的對象就是 "垃圾",直接釋放它們的內存。

這種方式解決了引用計數法的 "循環引用" 問題。比如兩個對象互相引用,但都不再被全局訪問,標記階段它們不會被標記,清除階段會被回收 —— 而引用計數法會因為它們互相引用,計數不為 0,永遠不回收,導致內存泄漏。

第二步:標記 - 整理

標記 - 清除后,堆內存會像被挖過的地一樣坑坑洼洼:存活對象零散分布,中間夾雜著被回收的空白區域(內存碎片)。下次想分配一個大對象,可能找不到連續的空間,明明總內存夠,卻分配失敗。

所以 V8 會緊接著做 "標記 - 整理":把所有存活對象往內存的一端 "擠",讓空白區域集中到另一端,形成一整塊連續的空閑內存。就像把衣柜里的衣服都推到左邊,右邊留出一大塊空地放新衣服。

老生代的"增量標記"

JS 是單線程的,一旦開始垃圾回收,JS 代碼就會暫停(稱為 "Stop-The-World")。如果老生代內存很大,一次完整的標記 - 清除可能要卡 1 秒以上 —— 用戶點按鈕沒反應,頁面像死機了一樣。

為了解決這個問題,V8 用了增量標記:把原本一口氣完成的標記階段,拆成一小塊一小塊,穿插在 JS 代碼執行間隙。比如標記 10ms,就讓 JS 執行 20ms,再標記 10ms... ,如果循環,直到標記階段完成才進入內存碎片的整理上面來,不耽誤JS代碼的正常執行。

這樣一來,單次垃圾回收的阻塞時間從幾百毫秒降到幾十毫秒,用戶幾乎感覺不到卡頓。數據顯示,增量標記能把垃圾回收的阻塞時間減少到原來的 1/6,對大型應用來說太重要了。

最后

搞懂 V8 的回收機制后,我總結了幾個對開發有用的點:

  1. 少創建臨時對象:循環、頻繁調用的函數里,盡量復用對象(比如把const obj = { ... }提到循環外),減少新生代回收壓力。
  2. 及時解除引用:不用的全局變量、定時器、事件監聽,記得設為null,讓對象失去引用,被及時回收。
  3. 小心閉包陷阱:閉包會讓內部對象被長期引用,比如function create() { const data = bigObject; return () => data; },data會一直存在老生代,不用時要手動解除引用。

?轉自https://juejin.cn/post/7524812060761489418


該文章在 2025/7/10 9:53:21 編輯過
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 人人添人人 | 欧美在线播放成人a | 精品国语自产拍在线 | 欧美日韩综合精品网 | 区三区夜夜嗨 | 日韩大片免费观 | 国产换战精精品 | 国产激情影视在线 | 日韩性生活| 国产视频三级 | 日本乱码视频文字幕 | 国产黄A | 国产在线一二三区 | 成人天堂2025 | 日韩精品a∨片蜜臀 | 日韩欧美在线综合网 | 欧美自拍视频 | 三级经典国产精品 | 国产不卡2区 | 精品国产自在91欧 | 96网友上传国产 | 欧美日韩国产偷拍 | 国产永久观看在线 | 國產精品 | 国产在线观看v片 | 午夜成人免费影院 | 午夜成人激情视频 | 91新视频 | 国产精品第一二三区 | 国产精品女主播 | 亚洲无码日 | 精品国产柚木在线 | 日韩福利导航地址一 | 日韩经典视频 | 绿帽一区二区 | 国产呦福利导航 | 国产黄页 | 国产乱子伦精品视频 | 国产网站一区二 | 欧美日韩亚洲另 | 午夜成人福利 |