久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網
      最全最豐富的資訊網站

      聊聊V8的內存管理與垃圾回收算法

      本篇文章帶大家了解一下V8引擎的內存管理與垃圾回收算法,希望對大家有所幫助!

      聊聊V8的內存管理與垃圾回收算法

      眾所周知,JS是自動管理垃圾回收的,開發(fā)者不需要關心內存的分配與回收。而且垃圾回收機制在前端面試中也是??嫉牟糠?。本文主要講解V8的分代垃圾回收算法,希望閱讀本文后的小伙伴能夠對V8垃圾回收機制有個痛徹(哈哈,是痛徹?。。。┑牧私?,文章主要涵蓋如下內容:

      • V8的內存限制與解決辦法
      • 新生代內存對象的Scavenge算法
      • 基于可達性分析算法標記存活對象的邏輯以及優(yōu)化手段
      • 新生代內存對象的晉升條件、
      • Scavenge算法的深度/廣度優(yōu)先區(qū)別
      • 跨代內存的的寫屏障
      • 老生代內存對象的標記清除/整理算法
      • GCSTW原因及優(yōu)化策略

      V8的內存限制與解決辦法

      V8最初為瀏覽器設計,遇到大內存使用的場景較少,在設計上默認對內存使用存在限制,只允許使用部分內存,64位系統(tǒng)可允許使用內存約1.4g,32位系統(tǒng)約0.7g。如下代碼所示,在Node中查看所依賴的V8引擎的內存限制方法:

      process.memoryUsage();  // 返回內存的使用量,單位字節(jié) {   rss: 22953984,   // 申請的總的堆內存   heapTotal: 9682944,   // 已使用的堆內存   heapUsed: 5290344,   external: 9388 }

      聊聊V8的內存管理與垃圾回收算法

      V8限制內存使用大小還有另一個重要原因,堆內存過大時V8執(zhí)行垃圾回收的時間較久(1.5g50ms),做非增量式的垃圾回收要更久(1.5g1s)。在后續(xù)講解了V8的垃圾回收機制后相信大家更能感同身受。

      雖然V8引擎對內存使用做了限制,但是同樣暴露修改內存限制的方法,就是啟動V8引擎時添加相關參數(shù),下面代碼演示在Node中修改依賴的V8引擎內存限制:

      # 更改老生代的內存限制,單位mb node --max-old-space-size=2048 index.js  # 更改新生代的內存限制,單位mb node --max-semi-space-size=1024=64 index.js

      這里需要注意的是更改的新生代的內存的語法已經更改為上述的寫法,且單位也由kb變成了mb,舊的寫法是node --max-new-space-size,可以通過下面命令查詢當前Node環(huán)境修改新生代內存的語法:

      node --v8-options | grep max

      聊聊V8的內存管理與垃圾回收算法

      V8垃圾回收策略

      在引擎的垃圾自動回收機制的歷史演變中,人們發(fā)現(xiàn)是沒有一種通用的可以解決任何場景下垃圾回收的算法的。因此現(xiàn)代垃圾回收算法根據(jù)對象的存活時間將內存垃圾進行分代,分代垃圾回收算法就是對不同類別的內存垃圾實行不同的回收算法。

      V8將內存分為新生代老生代兩種:

      • 新生代內存中的對象存活時間較短
      • 老生代內存中代對象存活時間較長或是常駐內存

      新生代內存存放在新生代內存空間(semispace)中,老生代內存存放在老生代內存空間中(oldspace),如下圖所示:

      聊聊V8的內存管理與垃圾回收算法

      • 新生代內存采用Scavenge算法
      • 老生代內存采用Mark-SweepMark-Compact算法

      下面我們看看Scavenge的算法邏輯吧!

      Scavenge算法

      對于新生代內存的內存回收采用Scavenge算法,Scavenge的具體實現(xiàn)采用的是Cheney算法。Cheney算法是將新生代內存空間一分為二,一個空間處于使用狀態(tài)(FromSpace),一個空間處于空閑狀態(tài)(稱為ToSpace)。

      聊聊V8的內存管理與垃圾回收算法

      在內存開始分配時,首先在FromSpace中進行分配,垃圾回收機制執(zhí)行時會檢查FromSpace中的存活對象,存活對象會被會被復制到ToSpace,非存活對象所占用的空間將被釋放,復制完成后FromSpaceToSpace的角色將翻轉。當一個對象多次復制后依然處于存活狀態(tài),則認為其是長期存活對象,此時將發(fā)生晉升,然后該對象被移動到老生代空間oldSpace中,采用新的算法進行管理。

      聊聊V8的內存管理與垃圾回收算法

      Scavenge算法其實就是在兩個空間內來回復制存活對象,是典型的空間換時間做法,所以非常適合新生代內存,因為僅復制存活的對象且新生代內存中存活對象是占少數(shù)的。但是有如下幾個重要問題需要考慮:

      • 引用避免重復拷貝

      假設存在三個對象temp1、temp2、temp3,其中temp2、temp3都引用了temp1,js代碼示例如下:

      var temp2 = {   ref: temp1, }  var temp3 = {   ref: temp1, }  var temp1 = {}

      FromSpace中拷貝temp2ToSpace中時,發(fā)現(xiàn)引用了temp1,便把temp1也拷貝到ToSpace,是一個遞歸的過程。但是在拷貝temp3時發(fā)現(xiàn)也引用了temp1,此時再把temp1拷貝過去則重復了。

      要避免重復拷貝,做法是拷貝時給對象添加一個標記visited表示該節(jié)點已被訪問過,后續(xù)通過visited屬性判斷是否拷貝對象。

      • 拷貝后保持正確的引用關系

      還是上述引用關系,由于temp1不需要重復拷貝,temp3被拷貝到ToSpace之后不知道temp1對象在ToSpace中的內存地址。

      做法是temp1被拷貝過去后該對象節(jié)點上會生成新的field屬性指向新的內存空間地址,同時更新到舊內存對象的forwarding屬性上,因此temp3就可以通過舊temp1forwarding屬性找到在ToSpace中的引用地址了。

      內存對象同時存在于新生代和老生代之后,也帶來了問題:

      • 內存對象跨代(跨空間)后如何標記
      const temp1 = {}  const temp2 = {   ref: temp1, }

      比如上述代碼中的兩個對象temp1temp2都存在于新生代,其中temp2引用了temp1。假設在經過GC之后temp2晉升到了老生代,那么在下次GC的標記階段,如何判斷temp1是否是存活對象呢?

      在基于可達性分析算法中要知道temp1是否存活,就必須要知道是否有根對象引用引用了temp1對象。如此的話,年輕代的GC就要遍歷所有的老生代對象判斷是否有根引用對象引用了temp1對象,如此的話分代算法就沒有意義了。

      解決版本就是維護一個記錄所有的跨代引用的記錄集,它是寫緩沖區(qū)的一個列表。只要有老生代中的內存對象指向了新生代內存對象時,就將老生代中該對象的內存引用記錄到記錄集中。由于這種情況一般發(fā)生在對象寫的操作,顧稱此為寫屏障,還一種可能的情況就是發(fā)生在晉升時。記錄集的維護只要關心對象的寫操作和晉升操作即可。此是又帶來了另一個問題:

      • 每次寫操作時維護記錄集的額外開銷

      優(yōu)化的手段是在一些Crankshaft操作中是不需要寫屏障的,還有就是棧上內存對象的寫操作是不需要寫屏障的。還有一些,

      贊(0)
      分享到: 更多 (0)
      網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號