亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Node(V8)的垃圾回收機制

suxier / 899人閱讀

摘要:基本概念垃圾回收機制。對兩個不同生代的不同垃圾回收策略構(gòu)成了整個的垃圾回收機制。此種方式會導(dǎo)致下一次內(nèi)存中產(chǎn)生大量碎片,即內(nèi)存空間不連續(xù),導(dǎo)致內(nèi)存分配時面對大對象可能會無法滿足,提前出發(fā)下一次的垃圾回收機制。

: 聊一聊垃圾回收機制吧。
: 恩,垃圾回收是自動的。
基本概念

GC(Garbage collection)垃圾回收機制。目的是解釋器去判別需要回收的內(nèi)容,當(dāng)解釋器認(rèn)為一個占著房子的人已經(jīng)沒有存在的意義了,就自動收回房子重新對外出租(available)。JS和PY都選擇不相信程序員,選擇自己操控內(nèi)存問題。

Node的對象都是分配在堆內(nèi)存上,V8主要把內(nèi)存分為 new-space 和 old-space ,64位系統(tǒng)對應(yīng)的大小約為 32MB 和 1400MB(32位系統(tǒng)對應(yīng)折半)。二者共同構(gòu)成Node的總內(nèi)存(約為1.4G)。

新生代空間的對象生存周期比較短,容量也比較小,老生代的對象都是“強硬派”,生命力旺盛,容量比較大。Node 不是 HipHop 為啥非要把內(nèi)存分這個 “new-school”,“old-school” ?,就是因為在實際的情況中,各種垃圾回收策略并不能滿足解決不同的對象聲明周期長短不一的問題,而只是針對某一種特定情況非常有用,所以基于分代策略能夠根據(jù)對象的生命周期不同,采用最適合的算法策略進行高效垃圾回收。

Node對兩個不同生代的不同垃圾回收策略構(gòu)成了整個Node的垃圾回收機制。下面就來詳細(xì)說明這兩個不同的生代究竟是怎么處理的辣雞的。

new-space 與 Scavenge算法

回顧一下 new-space 的特點:對象的生存周期普遍都比較短。這意味著,“頑固派”對象比較少

Scavenge 策略把 new-space 一分為兩個 “simispace"(半空間),一個叫 處于使用狀態(tài)的 From 空間 一個叫閑置的 TO 空間。整個回收的過程就是如下圖:

引用計數(shù)與閉包

那么在新生代中如何讓GC知道某一個對象已經(jīng)沒有價值即該對象的生命周期已經(jīng)結(jié)束了呢?

引用計數(shù):所謂引用計數(shù)就是跟蹤并記錄每一個值被引用的次數(shù),當(dāng)我們生命了一個變量并且將一個引用類型賦值給該變量,那么該引用對象的引用計數(shù)加一,如果同一個變量又賦值給了另外一個變量,那么計數(shù)再一次增加1。那么相反的是如果某一個有引用類型值得變量又被賦了另外一個值,那么原先的引用類型的計數(shù)就相應(yīng)的減一,或者當(dāng)在一個函數(shù)執(zhí)行完畢之后,該函數(shù)在執(zhí)行時所創(chuàng)建的作用域?qū)N毀,與此同時在該函數(shù)作用域中聲明的局部變量所對應(yīng)的內(nèi)存空間的引用計數(shù)將隨之減一,不出現(xiàn)閉包的情況下,下一次的垃圾回收機制在被觸發(fā)的時候,作用域中的變量所對應(yīng)的空間就會結(jié)束聲明周期。像下面的代碼那樣:

function callOnce(){
    let local = {}
    let foo = {}
    let bar = {a:{},b:{}}
}

那么所謂閉包,一個在面試中都快被問爛了的概念:),其實說白了就是運用函數(shù)可以作為參數(shù)或者返回值使得一個外部作用域想要訪問內(nèi)部作用域中的私有變量的一種方式

function foo(){
    let local = {a:"ray"}
    return function(){
        return local
    }
}

let bar = foo()

上述代碼就形成了一個閉包,使得一旦有了變量引用了foo函數(shù)的返回值函數(shù),就使得該返回值函數(shù)得不到釋放,也使得foo函數(shù)的作用域得不到釋放,即內(nèi)存也不會釋放,除非不再有引用,才會逐步釋放。

old-space 與 標(biāo)記-清除/標(biāo)記-整理

分代之中除了 new-space 之外即是 old-space 了 ,分代的目的是為了針對不同的對象生命周期運用不同的回收算法。

滿足條件晉升到老生代的的對象都有著比較頑強的生機,意味著在老生代中,存活的對象占有者很大的比重,使用新生代基于復(fù)制的策略會有著比較差的效率,此外,新生代中一分為二的空間策略面對著存活對象較多的情況也比較不合適。所以在老生代中V8采用了標(biāo)記-清除與標(biāo)記-整理這這兩種方式結(jié)合的策略。

標(biāo)記清除分為標(biāo)記和清除兩個步驟,先在老生代中遍歷所有的對象,把那些在遍歷過程中還活著的對象都加上一個標(biāo)記,在下一步的時候那些沒有被標(biāo)記的對象就會自然的被回收了。示意圖如下:

黑色的即為沒有被標(biāo)記已經(jīng)死了對象,下一次就會被回收內(nèi)存空間。

此種方式會導(dǎo)致下一次內(nèi)存中產(chǎn)生大量碎片,即內(nèi)存空間不連續(xù),導(dǎo)致內(nèi)存分配時面對大對象可能會無法滿足,提前出發(fā)下一次的垃圾回收機制。所以便又有了一種標(biāo)記-整理的方式。

對比標(biāo)記-清除,他多了異步整理的過程,即把標(biāo)記為存活的兌現(xiàn)統(tǒng)統(tǒng)整理到內(nèi)存的一端,完成整理之后直接清除掉另一端連續(xù)的死亡對象空間,如下:

最后,由于標(biāo)記-整理這種方式設(shè)計大量移動對象操作,導(dǎo)致速度非常慢,多以 V8 主要使用標(biāo)記-清除的方式,當(dāng)老生代空間中不足以為新生代晉升過來的頑固派們分配空間的時候,才使用標(biāo)記-整理

V8的優(yōu)化

由于在進行垃圾回收的時候會導(dǎo)致應(yīng)用邏輯陷入全停頓的狀態(tài),在進行老生代的回收時,V8引入了 增量式標(biāo)記,增量式整理,延遲清理等策略,中心思想就是為了能讓一次垃圾回收過程不那么占用太長的應(yīng)用程序停頓時間,而提出類似于時間片輪轉(zhuǎn)一樣的策略,讓整個過程“雨露均沾”,GC弄一會,應(yīng)用程序執(zhí)行一會。

堆內(nèi)內(nèi)存與堆外內(nèi)存

使用process.memoryUsage()可以查看node進程的內(nèi)存使用情況。單位是字節(jié)

{ rss: 22233088,
  heapTotal: 7708672,
  heapUsed: 5095384,
  external: 28898 }

其中 rss 就是 node 進程的常駐內(nèi)存。V8對內(nèi)存有限制,但是不同于瀏覽器,Node在服務(wù)端難免會操作大文件流,所以有了一種跳脫 V8 的內(nèi)存限制方式就是使用 buffer 進行堆外內(nèi)存分配。如下代碼:

let showMem = () => {
    let mem = process.memoryUsage()
    //process.memoryUsage()值得單位都是字節(jié),轉(zhuǎn)化為兆
    let format = (byte) => {
        return (byte/1024/1024).toFixed(2)+"MB"
    }
    console.log(`rss:${format(mem.rss)}
 heapTotal:${format(mem.heapTotal)}
 heapUsed:${format(mem.heapUsed)}
 external:${format(mem.external)}`);
    console.log("------------------------------------");
}

let useMem = () => {
    let size = 20*1024*1024
    let arr = new Array(size)
    for (let index = 0; index < size; index++) {
        arr[index] = 0      
    }
    return arr
}

let useMemBuffer = () => {
    let size = 20*1024*1024
    let buf = new Buffer(size)
    for (let index = 0; index < size; index++) {
        buf[index] = 0      
    }
    return buf
}

let total = []

for (let index = 0; index < 100; index++) {
    showMem()
    total.push(useMemBuffer())
}

showMem()

下面為分別調(diào)用 useMem()useMemBuffer() 使用數(shù)組是通過V8分配堆內(nèi)存,使用 Buffer 是不使用V8分配堆外內(nèi)存,分別打?。?/p>

上圖一表示堆內(nèi)內(nèi)存在一定循環(huán)次數(shù)之后達(dá)到溢出邊緣,

圖二可見,externalrss在不斷增大但是其值早就突破了V8的內(nèi)存上限。是因為堆外內(nèi)存并不是V8進行內(nèi)存分配的。

下一篇所要討論的緩存算法中,緩存就是一個有可能造成內(nèi)存泄漏的場景。

參考:

《深入淺出NodeJS》-- 樸靈

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/93505.html

相關(guān)文章

  • Node.js內(nèi)存管理和V8垃圾回收機制

    摘要:垃圾回收內(nèi)存管理實踐先通過一個來看看在中進行垃圾回收的過程是怎樣的內(nèi)存泄漏識別在環(huán)境里提供了方法用來查看當(dāng)前進程內(nèi)存使用情況,單位為字節(jié)中保存的進程占用的內(nèi)存部分,包括代碼本身棧堆。 showImg(https://segmentfault.com/img/remote/1460000019894672?w=640&h=426);作者 | 五月君Node.js 技術(shù)棧 | https:...

    JowayYoung 評論0 收藏0
  • Node - 內(nèi)存管理和垃圾回收

    摘要:的內(nèi)存限制和垃圾回收機制內(nèi)存限制內(nèi)存限制一般的后端語言開發(fā)中,在基本的內(nèi)存使用是沒有限制的。的內(nèi)存分代目前沒有一種垃圾自動回收算法適用于所有場景,所以的內(nèi)部采用的其實是兩種垃圾回收算法。 前言 從前端思維轉(zhuǎn)變到后端, 有一個很重要的點就是內(nèi)存管理。以前寫前端因為只是在瀏覽器上運行, 所以對于內(nèi)存管理一般不怎么需要上心, 但是在服務(wù)器端, 則需要斤斤計較內(nèi)存。 V8的內(nèi)存限制和垃圾回收機...

    joyqi 評論0 收藏0
  • V8引擎】淺析Chrome V8引擎中垃圾回收機制和內(nèi)存泄露優(yōu)化策略

    摘要:一前言的垃圾回收機制使用垃圾回收機制來自動管理內(nèi)存。垃圾回收器只會針對新生代內(nèi)存區(qū)老生代指針區(qū)以及老生代數(shù)據(jù)區(qū)進行垃圾回收。分別對新生代和老生代使用不同的垃圾回收算法來提升垃圾回收的效率。 V8 實現(xiàn)了準(zhǔn)確式 GC,GC 算法采用了分代式垃圾回收機制。因此,V8 將內(nèi)存(堆)分為新生代和老生代兩部分。 一、前言 V8的垃圾回收機制:JavaScript使用垃圾回收機制來自動管理內(nèi)存。垃...

    qingshanli1988 評論0 收藏0
  • 淺談V8引擎中垃圾回收機制

    摘要:新生代的對象為存活時間較短的對象,老生代中的對象為存活時間較長或常駐內(nèi)存的對象。分別對新生代和老生代使用不同的垃圾回收算法來提升垃圾回收的效率。如果指向老生代我們就不必考慮它了。 這篇文章的所有內(nèi)容均來自 樸靈的《深入淺出Node.js》及A tour of V8:Garbage Collection,后者還有中文翻譯版V8 之旅: 垃圾回收器,我在這里只是做了個記錄和結(jié)合 垃圾回收...

    happen 評論0 收藏0
  • 簡述JavaScript垃圾回收機制

    摘要:關(guān)鍵是釋放內(nèi)存這一步,各種語言都有自己的垃圾回收簡稱機制。用的是這種,在字末位進行標(biāo)識,為指針。對于而言,最初的垃圾回收機制,是基于引用計次來做的。老生代的垃圾回收,分兩個階段標(biāo)記清理有和這兩種方式。 不管是高級語言,還是低級語言。內(nèi)存的管理都是: 分配內(nèi)存 使用內(nèi)存(讀或?qū)懀?釋放內(nèi)存 前兩步,大家都沒有太大異議。關(guān)鍵是釋放內(nèi)存這一步,各種語言都有自己的垃圾回收(garbage ...

    wenshi11019 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<