V8 引擎垃圾回收與內存分配

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"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":"工欲善其事,必先利其器,本文之器非器具之器,乃容器也,言歸正傳,作爲一個前端打工人,左手剛 const 定義常量,忠貞不二,轉頭就 new 幾個對象,玩的火熱,真是個優秀的 jser,風騷的操作背後,必有日夜不輟的 QWER,外加一個走 A,廢話不多說,瀏覽器內核是啥玩意?還不知道都有啥瀏覽器內核?那就先來看看瀏覽器內核。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"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":"提到瀏覽器內核,Blink、Weikit、Gecko、Trident 張口就來,這些只是各個瀏覽器內核的組成部分之一渲染引擎,對應的還有 JavaScript引擎,簡單羅列一下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"
瀏覽器渲染引擎Javascript 引擎
ChromeBlink(13 年之前使用的是 Safari 的 Webkit, Blink 是谷歌與歐朋一起搞的)V8
SafariWebkitJavaScriptCore
FirefoxGeckoSpiderMonkey--OdinMonkey
IETridentChakra"}}},{"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":"渲染引擎和 JS 引擎相互協作,打造出瀏覽器顯示的頁面,看下圖:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/1a\/1a95c7604cfe213d01b9efe3d4a08a6c.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"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":"簡單看看就行,不重要,既然是講垃圾回收( Garbage Collection 簡稱 GC ),那就要先去回收站了,回收站有個學名叫:"},{"type":"text","marks":[{"type":"strong"}],"text":"內存"},{"type":"text","text":",計算機五大硬件之一存儲器的核心之一,見下圖:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/4e\/4e6e4b43a4b6853fc0a6634d9bb5b847.png","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"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":"說句更不重要的,JS 是沒有能力管理內存和垃圾回收的,一切都要依賴各個瀏覽器的 JS 引擎,所以爲了逼格更高一點,就不要說 JS 垃圾回收了,你看,我說 V8 垃圾回收,是不是厲害多了(摸了摸越來越沒有阻力的腦袋)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"內存分配"}]},{"type":"heading","attrs":{"align":null,"level":4},"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":4},"content":[{"type":"text","text":"堆"}]},{"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":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"V8 中內存分類"}]},{"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":"strong"}],"text":"弱分代假說"},{"type":"text","text":",V8 的垃圾回收主要建立在這個假說之上。"}]},{"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":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"絕大部分的對象生命週期都很短,即存活時間很短"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"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":"基於以上兩個概念,將內存分爲新生代 (new space)與老生代 (old space)兩個區域。劃重點,記一下。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"垃圾回收"}]},{"type":"heading","attrs":{"align":null,"level":4},"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","marks":[{"type":"strong"}],"text":"新生代"},{"type":"text","text":"(32 位系統分配 16M 的內存空間,64 位系統翻倍 32M,不同瀏覽器可能不同,但是應該差不了多少)。"}]},{"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":"新生代算法爲 Scavenge 算法,典型犧牲空間換時間的敗家玩意,怎麼說呢?首先他將新生代分爲兩個相等的半空間( semispace ) "},{"type":"text","marks":[{"type":"strong"}],"text":"from space"},{"type":"text","text":"  與 "},{"type":"text","marks":[{"type":"strong"}],"text":"to space"},{"type":"text","text":",來看看這個敗家玩意,是怎麼操作的,他使用寬度優先算法,是寬度優先,記住了不。兩個空間,同一時間內,只會有一個空間在工作( from space ),另一個在休息( to space )。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"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":"首先,V8 引擎中的垃圾回收器檢測到 from space 空間快達到上限了,此時要進行一次垃圾回收了"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"然後,從根部開始遍歷,不可達對象(即無法遍歷到的對象)將會"},{"type":"text","marks":[{"type":"strong"}],"text":"被標記"},{"type":"text","text":",並且複製"},{"type":"text","marks":[{"type":"strong"}],"text":"未被標記"},{"type":"text","text":"的對象,放到 to space 中"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"最後,清除 from space 中的數據,同時將 from space 置爲空閒狀態,即變成 to space,相應的 to space 變成 from space,俗稱翻轉"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/b7\/b77c23d739d4d9b84264e7ef45a7a284.png","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"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":"也是,你說空間都給他了,他愛咋地處理就咋地處理唄,總不可能強迫王校長開二手奧拓吧,當然了,對於小對象,這麼來一次,時間的優勢那是槓槓的,雖然浪費了一半空間,但是問題不大,能 hold 住。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然優秀的 V8 是不可能容忍,一個對象來回的在 form space 和 to space 中蹦躂的,當經歷一次 form => to 翻轉之後,發現某些未被標記的對象居然還在,會直接扔到老生代裏面去,好似後浪參加比賽,晉級了,優秀的嘞。"}]},{"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":"除了上面一種情況,還有一個情況也會晉級,當一個對象,在被複制的時候,大於 to space 空間的 25% 的時候,也會晉級了,這種自帶背景的選手,那是不敢動的,直接晉級到老生代。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"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","marks":[{"type":"strong"}],"text":"老生代"},{"type":"text","text":"( 32 位操作系統分配大約 700M 內存空間,64 位翻倍 1.4G,一樣,每個瀏覽器可能會有差異,但是差不了多少)。"}]},{"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":"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":"old object space"},{"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":"large object space"},{"type":"text","text":" 大對象存儲區域,其他區域無法存儲下的對象會被放在這裏,基本是超過 1M 的對象,這種對象不會在新生代對象中分配,直接存放到這裏,當然了,這麼大的數據,複製成本很高,基本就是在這裏等待命運的降臨不可能接受僅僅是知其然,而不知其所以然"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Map space"},{"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":"code space"},{"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":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a2\/a21535a049e3f03e463ce9e0d9a02274.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"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":"講了這麼多基本概念,聊聊最後的老生代回收算法,老生代回收算法爲:標記和清除\/整理(mark-sweep\/mark-compact)。"}]},{"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":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"白:未被標記的對象,即不可達對象(沒有掃描到的對象),可回收"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"灰:已被標記的對象(可達對象),但是對象還沒有被掃描完,不可回收"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"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":"當然,既然要標記,就需要提供記錄的坑位,在 V8 中分配的每一個內存頁中創建了一個 marking bitmap 坑位。"}]},{"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":"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":"首先將所有的非根部對象全部標記爲白色,然後使用深度優先遍歷,是深度優先哈,和新生代不一樣哈,按深度優先搜索沿途遍歷,將訪問到的對象,直接壓入棧中,同時將標記結果放在 marking bitmap (灰色) 中,一個對象遍歷完成,直接出棧,同時在 marking bitmap 中記錄爲黑色,直到棧空爲止,來張圖,休息一下"}]}]}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/94\/94f463cc51ef32417a06ed42aaa44510.webp","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"numberedlist","attrs":{"start":"2","normalizeStart":"2"},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"標記完成後,接下來就是等待垃圾回收器來清除了,清除完了之後,會在原來的內存區域留下一大堆不連續的空間,小對象還好說,這個時候如果來一個稍微大一點的對象,沒有內存可以放的下這個傻大個了,怎麼辦?只能觸發 GC,但是吧,原來清除的不連續的空間加起來又可以放的下這個傻大個,很可惜啊,啓動一次 GC 性能上也是嗖嗖的往下掉啊;V8 能容許這樣的事發生?肯定不存在嘛!"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"所以在清除完之後,新生代中對象,再一次分配到老生代並且內存不足的時候,會優先觸發標記整理(mark-compact), 在標記結束後,他會將可達對象(黑色),移到內存的另一端,其他的內存空間就不會被佔用,直接釋放,等下次再有對象晉升的時候,輕鬆放下。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看到這裏各位大佬可能會有疑問,那要是我 GC 搞完之後,再來個對象,滿了咋辦,你說咋辦,直接崩好不好,這個時候就需要大佬們寫代碼的時候,要珍惜內存了,對內存就像珍惜你的女朋友一樣,啥?沒有女朋友?那就沒辦法了,原則上是決不了這個問題的。"}]},{"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":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/72\/72a84cf9a6f97f30fd7fb7f70c4d5fca.png","alt":"Image","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"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":"想一個問題,當 GC 想回收新生代中的內容的時候,某些對象,只有一個指針指向了他,好巧不巧的是,這個指針還是老生代那邊對象指過來的,怎麼搞?我想回收這個玩意,難道要遍歷一下老生代中的對象嗎?這不是開玩笑嗎?爲了回收這一個玩意,我需要遍歷整個老生代,代價着實太大,搞不起,搞不起,那怎麼辦哩?"}]},{"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":"V8 引擎中有個概念稱作"},{"type":"text","marks":[{"type":"strong"}],"text":"寫屏障"},{"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":"在新生代中觸發 GC 遇到這樣的對象的時候,會首先讀一下緩存列表,這相比遍歷老生代所有的對象,代價實在是太小了,這操作值得一波 666,很優秀,當然了,關於 V8 引擎內在的優化,還有很多很多,各位大佬可以慢慢去了解。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"全停頓(stop-the-world)"}]},{"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 happy 就 good。"}]},{"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":"在以往,新\/老生代都包括在內,爲了保證邏輯和垃圾回收的情況不一致,需要停止 JS 的運行,專門來遍歷去遍歷\/複製,標記\/清除,這個停頓就是:全停頓。"}]},{"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":"所以在 V8 引擎在名爲 Orinoco 項目中,做了三個事情,當然只針對老生代,新生代這個後浪還是可以的,效率賊拉的高,優化空間不大。三個事情分別是:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"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":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將原來一口氣去標記的事情,做成分步去做,每次內存佔用達到一定的量或者多次進入寫屏障的時候,就暫時停止 JS 程序,做一次最多幾十毫秒的標記 marking,當下次 GC 的時候,反正前面都標記好了,開始清除就行了"}]},{"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":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從字面意思看並行,就是在一次全量垃圾回收的過程中,就是 V8 引擎通過開啓若干輔助線程,一起來清除垃圾,可以極大的減少垃圾回收的時間,很優秀,手動點贊"}]},{"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":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"併發就是在 JS 主線程運行的時候,同時開啓輔助線程,清理和主線程沒有任何邏輯關係的垃圾,當然,需要寫屏障來保障"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"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":"V8 引擎做的優化有很多,還有比如多次( 2 次)在新生代中能夠存活下來的對象,會被記錄下來,在下次 GC 的時候,會被直接晉升到老生代,還有比如新晉升的對象,直接標記爲黑色,這是因爲新晉升的對象存活下來的概率非常高,這兩種情況就算是不再使用,再下下次的時候也會被清除掉,影響不大,但是這個過程,第一種就省了新生代中的一次複製輪迴,第二種就省了 marking 的過程,在此類對象比較多的情況下,還是比較有優勢的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"頭圖:Unsplash"}]},{"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},"content":[{"type":"text","text":"原文:https:\/\/mp.weixin.qq.com\/s\/2ARruErg3xNlvPOYjw7IiA"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文:V8 引擎垃圾回收與內存分配"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"來源:政採雲前端團隊 - 微信公衆號 [ID:Zoo-Team]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"轉載:著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。"}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章