垃圾回收算法

v8的內存劃分
  • v8大致分爲,垃圾回收在堆裏進行。node

  • 堆內存分多個模塊:算法

    • New space瀏覽器

      大多數的對象開始都會被分配在這裏,這個區域相對較小可是垃圾回收特別頻繁,該區域被對半分爲兩半(分爲Semi space From 和 Semi space To )ide

    • Old space優化

      新生代中的對象在存活一段時間後就會被轉移到老生代內存區,相對於新生代該內存區域的垃圾回收頻率較低。spa

    • Large object space操作系統

      存放體積超越其餘區域大小的對象,每一個對象都會有本身的內存,垃圾回收不會移動大對象區。線程

    • Code spacecode

      代碼對象會被分配在這裏,惟一擁有執行權限的內存區域。對象

    • Cells pace

    • Property cell space

    • Map space

  • 垃圾回收發生在新生代(New space)和老生代(Old space)中。

新生代和老生代的內存大小

根據操做系統不一樣:32位爲0.7G,64位爲1.4G

新生代 老生代
32位系統 34M 700M
64位系統 64M 1400M

最新版V14內存爲2G

垃圾回收的算法

新生代使用的是Scavenge(新生代互換算法)

老生代如今使用的是Mark-Compact(標記整理算法),之前使用Mark-Sweep(標記清除算法),最古老的是引用計數算法

Scavenge

過程:

每次新加入的變量都會放入from,當from中內存佔滿時會開始執行垃圾回收:對from中不用的內存回收,還存在引用的內存會被複制到to中,當此次垃圾回收結束的時候會出現from中爲空,to中留下還存在引用的內存,這時會將from和to交換,最後就是from中留下有引用的內存,to中保持爲空。

由於From和To中各佔一半,而且To始終不會存放,因此會浪費一半的空間。該算法是使用空間換取時間,而老生代比新生代大不少,因此用該算法不合理。


引用計數法

過程:

查看是否有其它的對象在引用該對象,若是沒有則把它清除。

該方法沒法處理對象間的循環引用,容易形成內存泄漏。

在 IE 時代就被拋棄了。


Mark-Sweep

該算法是早先使用的算法,如今已經不被使用

過程:

垃圾回收會在內部構件一個根節點(能夠看做是瀏覽器中的window,node中的gelobal)。首先對老生代中的全部對象進行一次廣度掃描,查找到有對根節點引用的對象時會把它標記,最後將沒有標記的對象垃圾回收。

該算法沒有進行內存的碎片整理,因此之後再須要非陪一個大的對象時會提早觸發垃圾回收,爲解決這個問題就產生了Mark-Compact(標記整理算法)


Mark-Compact

在標記清除法的基礎上進行了優化:

  • 它在執行垃圾回收的開始把全部被標記內存移動到一塊兒,而後清除未被標記的內存,這樣就解決了大對象存入時連續空間不足的問題。

  • 原先的Mark-Sweep算法會在執行垃圾回收時進行一次廣度掃描,將全部有引用節點標記,這叫作全停頓標記,由於JS是單線程的,因此一次垃圾回收的時間內所有標記對時間的花費會比較大;而如今則是使用增量標記法和三色標記法來進行標記。

增量標記法和三色標記法

將代碼運行和垃圾回收之間的且換變得更加頻繁,而且每次垃圾回收的時候只向下查找一層。

該算法把每一個節點分爲三種狀態:

  • 白色:沒有被查找的
  • 灰色:下次從這裏開始查找,引用該對象的對象沒有被查找到
  • 黑色:被標記的,引用該對象的對象已經被查找過了

三色標記法

每次垃圾回收時都進行一次查找,直到引用樹所有標黑後再進行排序-回收。

該模式將每次垃圾回收的標記拆分開插入代碼的運行中,比原先的全停頓標記法體驗更好。(在後續也引入了增量式整理和延遲清理,讓停頓變得更短)


新生代晉升到老生代

這個判斷很簡單:

  • 首先判斷該內存是否經歷過一次垃圾回收,沒經歷過的會放入to中。
  • 而後判斷這時to是否已經使用了25%(8M),若是沒有也會放入to中。
  • 兩個條件都判斷爲true時會被晉升到老生代中。
相關文章
相關標籤/搜索