摘要:關(guān)鍵是釋放內(nèi)存這一步,各種語言都有自己的垃圾回收簡稱機(jī)制。用的是這種,在字末位進(jìn)行標(biāo)識,為指針。對于而言,最初的垃圾回收機(jī)制,是基于引用計(jì)次來做的。老生代的垃圾回收,分兩個(gè)階段標(biāo)記清理有和這兩種方式。
不管是高級語言,還是低級語言。內(nèi)存的管理都是:
分配內(nèi)存
使用內(nèi)存(讀或?qū)懀?/p>
釋放內(nèi)存
前兩步,大家都沒有太大異議。關(guān)鍵是釋放內(nèi)存這一步,各種語言都有自己的垃圾回收(garbage collection, 簡稱GC)機(jī)制。做GC的第一步是判斷堆中存的是數(shù)據(jù)還是指針,是指針的話,說明它被指向活躍的對象。有3種判斷方法:
Conservative:如果存儲格式是地址,就認(rèn)為是。C/C++有用到這種算法。
Compiler hints:對于靜態(tài)語言,比如Java,編譯器是知道它是不是指針的,所以可以用這種。
Tagged pointers:JavaScript用的是這種,在字末位進(jìn)行標(biāo)識,1為指針。
對于JavaScript而言,最初的垃圾回收機(jī)制,是基于引用計(jì)次來做的。后來升級為標(biāo)記清除。
引用計(jì)次當(dāng)對象被引用次數(shù)為0時(shí),就被回收。潛在的一個(gè)問題是:循環(huán)引用時(shí),兩個(gè)對象都至少被引用了一次,將不能自動(dòng)被回收。所以導(dǎo)致,我們常講的內(nèi)存泄露。
// 引用計(jì)次 var a = {t: 1}; // 對象 `{t: 1}` (以下簡稱obj)被引用一次 var b = a; // obj 被引用兩次 a = null; // obj 現(xiàn)在為1次 b = null; // obj 現(xiàn)在為0次,可回收 // 循環(huán)引用 function fn() { var a = {}; var b = {}; a.b = b; b.a = a; } fn();標(biāo)記清除
這是當(dāng)前主流的GC算法,V8里面就是用這種。當(dāng)對象,無法從根對象沿著引用遍歷到,即不可達(dá)(unreachable),進(jìn)行清除。對于上面的例子,fn() 里面的 a 和 b 在函數(shù)執(zhí)行完畢后,就不能通過外面的上下文進(jìn)行訪問了,所以就可以清除了。
下面,我們簡述下V8的GC機(jī)制:
V8的GC機(jī)制在大部分的應(yīng)用場景:一個(gè)新創(chuàng)建的對象,生命周期通常很短。所以,V8里面,GC處理分為兩大類:新生代和老生代。
新生代的堆空間為1M~8M,而且被平分成兩份(to-space和from-space),通常一個(gè)新創(chuàng)建的對象,內(nèi)存被分配在新生代。當(dāng)to-space滿的時(shí)候,to-space和form-space交換位置(此時(shí),to空,from滿),并執(zhí)行GC.如果一個(gè)對象被斷定為,未被引用,就清除;有被引用,逃逸次數(shù)+1(如果此時(shí)逃逸次數(shù)為2,就移入老生代,否則移入to-space)。
老生代的堆空間大,GC不適合像新生代那樣,用平分成兩個(gè)space這種空間換時(shí)間的方式。老生代的垃圾回收,分兩個(gè)階段:標(biāo)記、清理(有Sweeping和Compacting這兩種方式)。
標(biāo)記,采用3色標(biāo)記:黑、白、灰。步驟如下:
GC開始,所以對象標(biāo)記為白色。
根對象標(biāo)記為黑色,并開始遍歷其子節(jié)點(diǎn)(引用的對象)。
當(dāng)前被遍歷的節(jié)點(diǎn),標(biāo)記為灰色,被放入一個(gè)叫 marking bitmap 的棧。在棧中,把當(dāng)前被遍歷的節(jié)點(diǎn),標(biāo)記為黑色,并出棧,同時(shí),把它的子節(jié)點(diǎn)(如果有的話)標(biāo)記為灰色,并壓入棧。(大對象比較特殊,這里不展開)
當(dāng)所有對象被遍歷完后,就只剩下黑和白。通過Sweeping或Compacting的方式,清理掉白色,完成GC。
小補(bǔ)充:JavaScript的根對象GC的時(shí)候,從根對象開始遍歷。在瀏覽器,根對象是 window;在 Node.js 中,是 global(或稱為root).
Node.js中,每個(gè)文件被當(dāng)做一個(gè)模塊,所以,當(dāng)你用 var/let/const 在文件的全局,聲明變量的時(shí)候,作用域是當(dāng)前文件(模塊)。因此,圖中 root.a 是 undefined.
Links:Memory Management
What is the root object in Node.js
解讀 V8 GC Log(一): Node.js 應(yīng)用背景與 GC 基礎(chǔ)知識
解讀 V8 GC Log(二): 堆內(nèi)外內(nèi)存的劃分與 GC 算法
A tour of V8: Garbage Collection
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/88482.html
摘要:什么是線程餓死,什么是活鎖多線程中的忙循環(huán)是什么變量是什么變量和變量有什么不同類型變量提供什么保證能使得一個(gè)非原子操作變成原子操作嗎 JVM專題 showImg(https://segmentfault.com/img/remote/1460000019943435); (面試題+答案領(lǐng)取方式見個(gè)人主頁) Java 類加載過程? 描述一下 JVM 加載 Class 文件的原理機(jī)制? ...
摘要:還是老規(guī)矩,從易到難吧傳統(tǒng)的定時(shí)器,異步編程等。分配對象時(shí),先是在空間中進(jìn)行分配。內(nèi)存泄漏內(nèi)存泄漏是指程序中己動(dòng)態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi),導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。 showImg(https://segmentfault.com/img/bVbwkad?w=1286&h=876); 網(wǎng)上參差不棄的面試題,本文由淺入深,讓你在...
摘要:還是老規(guī)矩,從易到難吧傳統(tǒng)的定時(shí)器,異步編程等。分配對象時(shí),先是在空間中進(jìn)行分配。內(nèi)存泄漏內(nèi)存泄漏是指程序中己動(dòng)態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi),導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。 showImg(https://segmentfault.com/img/bVbwkad?w=1286&h=876); 網(wǎng)上參差不棄的面試題,本文由淺入深,讓你在...
摘要:垃圾收集器簡述全文共兩部分有基礎(chǔ)的讀者只需要閱讀第一部分垃圾收集器在最新幾個(gè)版本的發(fā)展第二部分為基礎(chǔ)部分垃圾收集器在最新幾個(gè)版本的發(fā)展垃圾收集器始見于版本在后續(xù)的幾個(gè)版本中對它進(jìn)行了優(yōu)化和改進(jìn)在中垃圾收集器增加了幾個(gè)可配置選項(xiàng)的自動(dòng)發(fā)現(xiàn)功能 G1垃圾收集器簡述 全文共兩部分,有基礎(chǔ)的讀者只需要閱讀第一部分G1垃圾收集器在最新幾個(gè)版本的發(fā)展,第二部分為基礎(chǔ)部分. G1垃圾收集器在最新幾個(gè)...
閱讀 3268·2023-04-25 22:47
閱讀 3779·2021-10-11 10:59
閱讀 2314·2021-09-07 10:12
閱讀 4269·2021-08-11 11:15
閱讀 3440·2019-08-30 13:15
閱讀 1757·2019-08-30 13:00
閱讀 976·2019-08-29 14:02
閱讀 1691·2019-08-26 13:57