摘要:垃圾回收內(nèi)存管理實(shí)踐先通過一個(gè)來看看在中進(jìn)行垃圾回收的過程是怎樣的內(nèi)存泄漏識(shí)別在環(huán)境里提供了方法用來查看當(dāng)前進(jìn)程內(nèi)存使用情況,單位為字節(jié)中保存的進(jìn)程占用的內(nèi)存部分,包括代碼本身?xiàng)6选?/p>
作者 | 五月君
Node.js 技術(shù)棧 | https://www.nodejs.red
慕課認(rèn)證作者 | https://imooc.com/u/2667395
對(duì)于 Node.js 服務(wù)端研發(fā)的同學(xué)來說,關(guān)于垃圾回收、內(nèi)存釋放這塊不需要向 C/C++ 的同學(xué)那樣在創(chuàng)建一個(gè)對(duì)象之后還需要手動(dòng)創(chuàng)建一個(gè) delete/free 這樣的一個(gè)操作進(jìn)行 GC(垃圾回收), Node.js 與 Java 一樣,由虛擬機(jī)進(jìn)行內(nèi)存自動(dòng)管理。
但是這樣并不表示就此可以高枕無憂了,在開發(fā)中可能由于疏忽或者程序錯(cuò)誤導(dǎo)致的內(nèi)存泄漏也是一個(gè)很嚴(yán)重的問題,所以做為一名合格的服務(wù)端研發(fā)工程師,還是有必要的去了解下虛擬機(jī)是怎樣使用內(nèi)存的,遇到問題才能從容應(yīng)對(duì)。
快速導(dǎo)航Nodejs中的GC
Nodejs垃圾回收內(nèi)存管理實(shí)踐
內(nèi)存泄漏識(shí)別
內(nèi)存泄漏例子
手動(dòng)執(zhí)行垃圾回收內(nèi)存釋放
V8垃圾回收機(jī)制
V8堆內(nèi)存限制
新生代與老生代
新生代空間 & Scavenge 算法
老生代空間 & Mark-Sweep Mark-Compact 算法
V8垃圾回收總結(jié)
內(nèi)存泄漏
全局變量
閉包
慎將內(nèi)存做為緩存
模塊私有變量?jī)?nèi)存永駐
事件重復(fù)監(jiān)聽
其它注意事項(xiàng)
內(nèi)存檢測(cè)工具
Nodejs中的GCNode.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行環(huán)境,這是來自 Node.js 官網(wǎng)的一段話,所以 V8 就是 Node.js 中使用的虛擬機(jī),在之后講解的 Node.js 中的 GC 其實(shí)就是在講 V8 的 GC。
Node.js 與 V8 的關(guān)系也好比 Java 之于 JVM 的關(guān)系,另外 Node.js 之父 Ryan Dahl 在選擇 V8 做為 Node.js 的虛擬機(jī)時(shí) V8 的性能在當(dāng)時(shí)已經(jīng)領(lǐng)先了其它所有的 JavaScript 虛擬機(jī),至今仍然是性能最好的,因此我們?cè)谧?Node.js 優(yōu)化時(shí),只要版本升級(jí)性能也會(huì)伴隨著被提升。
Nodejs垃圾回收內(nèi)存管理實(shí)踐先通過一個(gè) Demo 來看看在 Node.js 中進(jìn)行垃圾回收的過程是怎樣的?內(nèi)存泄漏識(shí)別
在 Node.js 環(huán)境里提供了 process.memoryUsage 方法用來查看當(dāng)前進(jìn)程內(nèi)存使用情況,單位為字節(jié)
rss(resident set size):RAM 中保存的進(jìn)程占用的內(nèi)存部分,包括代碼本身、棧、堆。
heapTotal:堆中總共申請(qǐng)到的內(nèi)存量。
heapUsed:堆中目前用到的內(nèi)存量,判斷內(nèi)存泄漏我們主要以這個(gè)字段為準(zhǔn)。
external: V8 引擎內(nèi)部的 C++ 對(duì)象占用的內(nèi)存。
/** * 單位為字節(jié)格式為 MB 輸出 */ const format = function (bytes) { return (bytes / 1024 / 1024).toFixed(2) + " MB"; }; /** * 封裝 print 方法輸出內(nèi)存占用信息 */ const print = function() { const memoryUsage = process.memoryUsage(); console.log(JSON.stringify({ rss: format(memoryUsage.rss), heapTotal: format(memoryUsage.heapTotal), heapUsed: format(memoryUsage.heapUsed), external: format(memoryUsage.external), })); }內(nèi)存泄漏例子
堆用來存放對(duì)象引用類型,例如字符串、對(duì)象。在以下代碼中創(chuàng)建一個(gè) Fruit 存放于堆中。
// example.js function Quantity(num) { if (num) { return new Array(num * 1024 * 1024); } return num; } function Fruit(name, quantity) { this.name = name this.quantity = new Quantity(quantity) } let apple = new Fruit("apple"); print(); let banana = new Fruit("banana", 20); print();
執(zhí)行以上代碼,內(nèi)存向下面所展示的,apple 對(duì)象 heapUsed 的使用僅有 4.21 MB,而 banana 我們對(duì)它的 quantity 屬性創(chuàng)建了一個(gè)很大的數(shù)組空間導(dǎo)致 heapUsed 飆升到 164.24 MB。
$ node example.js {"rss":"19.94 MB","heapTotal":"6.83 MB","heapUsed":"4.21 MB","external":"0.01 MB"} {"rss":"180.04 MB","heapTotal":"166.84 MB","heapUsed":"164.24 MB","external":"0.01 MB"}
我們?cè)趤砜聪聝?nèi)存的使用情況,根節(jié)點(diǎn)對(duì)每個(gè)對(duì)象都持有引用,則無法釋放任何內(nèi)容導(dǎo)致無法 GC,正如下圖所展示的
手動(dòng)執(zhí)行垃圾回收內(nèi)存釋放假設(shè) banana 對(duì)象我們不在使用了,對(duì)它重新賦予一些新的值,例如 banana = null,看下此刻會(huì)發(fā)生什么?
結(jié)果如上圖所示,無法從根對(duì)象在到達(dá)到 Banana 對(duì)象,那么在下一個(gè)垃圾回收器運(yùn)行時(shí) Banana 將會(huì)被釋放。
讓我們模擬一下垃圾回收,看下實(shí)際情況是什么樣的?
// example.js let apple = new Fruit("apple"); print(); let banana = new Fruit("banana", 20); print(); banana = null; global.gc(); print();
以下代碼中 --expose-gc 參數(shù)表示允許手動(dòng)執(zhí)行垃圾回收機(jī)制,將 banana 對(duì)象賦為 null 后進(jìn)行 GC,在第三個(gè) print 打印出的結(jié)果可以看到 heapUsed 的使用已經(jīng)從 164.24 MB 降到了 3.97 MB
$ node --expose-gc example.js {"rss":"19.95 MB","heapTotal":"6.83 MB","heapUsed":"4.21 MB","external":"0.01 MB"} {"rss":"180.05 MB","heapTotal":"166.84 MB","heapUsed":"164.24 MB","external":"0.01 MB"} {"rss":"52.48 MB","heapTotal":"9.33 MB","heapUsed":"3.97 MB","external":"0.01 MB"}
下圖所示,右側(cè)的 banana 節(jié)點(diǎn)沒有了任何內(nèi)容,經(jīng)過 GC 之后所占用的內(nèi)存已經(jīng)被釋放了。
V8垃圾回收機(jī)制垃圾回收是指回收那些在應(yīng)用程序中不在引用的對(duì)象,當(dāng)一個(gè)對(duì)象無法從根節(jié)點(diǎn)訪問這個(gè)對(duì)象就會(huì)做為垃圾回收的候選對(duì)象。這里的根對(duì)象可以為全局對(duì)象、局部變量,無法從根節(jié)點(diǎn)訪問指的也就是不會(huì)在被任何其它活動(dòng)對(duì)象所引用。V8堆內(nèi)存限制
內(nèi)存在服務(wù)端本來就是一個(gè)寸土寸金的東西,在 V8 中限制 64 位的機(jī)器大約 1.4GB,32 位機(jī)器大約為 0.7GB。因此,對(duì)于一些大內(nèi)存的操作需謹(jǐn)慎否則超出 V8 內(nèi)存限制將會(huì)造成進(jìn)程退出。
一個(gè)內(nèi)存溢出超出邊界限制的例子
// overflow.js const format = function (bytes) { return (bytes / 1024 / 1024).toFixed(2) + " MB"; }; const print = function() { const memoryUsage = process.memoryUsage(); console.log(`heapTotal: ${format(memoryUsage.heapTotal)}, heapUsed: ${format(memoryUsage.heapUsed)}`); } const total = []; setInterval(function() { total.push(new Array(20 * 1024 * 1024)); // 大內(nèi)存占用 print(); }, 1000)
以上例子中 total 為全局變量每次大約增長(zhǎng) 160 MB 左右且不會(huì)被回收,在接近 V8 邊界時(shí)無法在分配內(nèi)存導(dǎo)致進(jìn)程內(nèi)存溢出。
$ node overflow.js heapTotal: 166.84 MB, heapUsed: 164.23 MB heapTotal: 326.85 MB, heapUsed: 324.26 MB heapTotal: 487.36 MB, heapUsed: 484.27 MB heapTotal: 649.38 MB, heapUsed: 643.98 MB heapTotal: 809.39 MB, heapUsed: 803.98 MB heapTotal: 969.40 MB, heapUsed: 963.98 MB heapTotal: 1129.41 MB, heapUsed: 1123.96 MB heapTotal: 1289.42 MB, heapUsed: 1283.96 MB <--- Last few GCs ---> [87581:0x103800000] 11257 ms: Mark-sweep 1283.9 (1290.9) -> 1283.9 (1290.9) MB, 512.1 / 0.0 ms allocation failure GC in old space requested [87581:0x103800000] 11768 ms: Mark-sweep 1283.9 (1290.9) -> 1283.9 (1287.9) MB, 510.7 / 0.0 ms last resort GC in old space requested [87581:0x103800000] 12263 ms: Mark-sweep 1283.9 (1287.9) -> 1283.9 (1287.9) MB, 495.3 / 0.0 ms last resort GC in old space requested <--- JS stacktrace --->
在 V8 中也提供了兩個(gè)參數(shù)僅在啟動(dòng)階段調(diào)整內(nèi)存限制大小
分別為調(diào)整老生代、新生代空間,關(guān)于老生代、新生代稍后會(huì)做介紹。
--max-old-space-size=2048
--max-new-space-size=2048
當(dāng)然內(nèi)存也并非越大越好,一方面服務(wù)器資源是昂貴的,另一方面據(jù)說 V8 以 1.5GB 的堆內(nèi)存進(jìn)行一次小的垃圾回收大約需要 50 毫秒以上時(shí)間,這將會(huì)導(dǎo)致 JavaScript 線程暫停,這也是最主要的一方面。
新生代與老生代絕對(duì)大多數(shù)的應(yīng)用程序?qū)ο蟮拇婊钪芷诙紩?huì)很短,而少數(shù)對(duì)象的存活周期將會(huì)很長(zhǎng)為了利用這種情況,V8 將堆分為兩類新生代和老生代,新空間中的對(duì)象都非常小大約為 1-8MB,這里的垃圾回收也很快。新生代空間中垃圾回收過程中幸存下來的對(duì)象會(huì)被提升到老生代空間。
新生代空間由于新空間中的垃圾回收很頻繁,因此它的處理方式必須非常的快,采用的 Scavenge 算法,該算法由 C.J. Cheney 在 1970 年在論文 A nonrecursive list compacting algorithm 提出。
Scavenge 是一種復(fù)制算法,新生代空間會(huì)被一分為二劃分成兩個(gè)相等大小的 from-space 和 to-space。它的工作方式是將 from space 中存活的對(duì)象復(fù)制出來,然后移動(dòng)它們到 to space 中或者被提升到老生代空間中,對(duì)于 from space 中沒有存活的對(duì)象將會(huì)被釋放。完成這些復(fù)制后在將 from space 和 to space 進(jìn)行互換。
Scavenge 算法非??爝m合少量?jī)?nèi)存的垃圾回收,但是它有很大的空間開銷,對(duì)于新生代少量?jī)?nèi)存是可以接受的。
老生代空間新生代空間在垃圾回收滿足一定條件(是否經(jīng)歷過 Scavenge 回收、to space 的內(nèi)存占比)會(huì)被晉升到老生代空間中,在老生代空間中的對(duì)象都已經(jīng)至少經(jīng)歷過一次或者多次的回收所以它們的存活概率會(huì)更大。在使用 Scavenge 算法則會(huì)有兩大缺點(diǎn)一是將會(huì)重復(fù)的復(fù)制存活對(duì)象使得效率低下,二是對(duì)于空間資源的浪費(fèi),所以在老生代空間中采用了 Mark-Sweep(標(biāo)記清除) 和 Mark-Compact(標(biāo)記整理) 算法。
Mark-Sweep
Mark-Sweep 處理時(shí)分為標(biāo)記、清除兩個(gè)步驟,與 Scavenge 算法只復(fù)制活對(duì)象相反的是在老生代空間中由于活對(duì)象占多數(shù) Mark-Sweep 在標(biāo)記階段遍歷堆中的所有對(duì)象僅標(biāo)記活對(duì)象把未標(biāo)記的死對(duì)象清除,這時(shí)一次標(biāo)記清除就已經(jīng)完成了。
看似一切 perfect 但是還遺留一個(gè)問題,被清除的對(duì)象遍布于各內(nèi)存地址,產(chǎn)生很多內(nèi)存碎片。
Mark-Compact
在老生代空間中為了解決 Mark-Sweep 算法的內(nèi)存碎片問題,引入了 Mark-Compact(標(biāo)記整理算法),其在工作過程中將活著的對(duì)象往一端移動(dòng),這時(shí)內(nèi)存空間是緊湊的,移動(dòng)完成之后,直接清理邊界之外的內(nèi)存。
V8垃圾回收總結(jié)為何垃圾回收是昂貴的?V8 使用了不同的垃圾回收算法 Scavenge、Mark-Sweep、Mark-Compact。這三種垃圾回收算法都避免不了在進(jìn)行垃圾回收時(shí)需要將應(yīng)用程序暫停,待垃圾回收完成之后在恢復(fù)應(yīng)用邏輯,對(duì)于新生代空間來說由于很快所以影響不大,但是對(duì)于老生代空間由于存活對(duì)象較多,停頓還是會(huì)造成影響的,因此,V8 又新增加了增量標(biāo)記的方式減少停頓時(shí)間。
關(guān)于 V8 垃圾回收這塊筆者講的很淺只是自己在學(xué)習(xí)過程中做的總結(jié),如果你想了解更多原理,深入淺出 Node.js 這本書是一個(gè)不錯(cuò)的選擇,還可參考這兩篇文章 A tour of V8: Garbage Collection、 Memory Management Reference.。
內(nèi)存泄漏內(nèi)存泄漏(Memory Leak)是指程序中己動(dòng)態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi),導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。全局變量
未聲明的變量或掛在全局 global 下的變量不會(huì)自動(dòng)回收,將會(huì)常駐內(nèi)存直到進(jìn)程退出才會(huì)被釋放,除非通過 delete 或 重新賦值為 undefined/null 解決之間的引用關(guān)系,才會(huì)被回收。關(guān)于全局變量上面舉的幾個(gè)例子中也有說明。
閉包這個(gè)也是一個(gè)常見的內(nèi)存泄漏情況,閉包會(huì)引用父級(jí)函數(shù)中的變量,如果閉包得不到釋放,閉包引用的父級(jí)變量也不會(huì)釋放從而導(dǎo)致內(nèi)存泄漏。
一個(gè)真實(shí)的案例 — The Meteor Case-Study,2013年,Meteor 的創(chuàng)建者宣布了他們遇到的內(nèi)存泄漏的調(diào)查結(jié)果。有問題的代碼段如下
var theThing = null var replaceThing = function () { var originalThing = theThing var unused = function () { if (originalThing) console.log("hi") } theThing = { longStr: new Array(1000000).join("*"), someMethod: function () { console.log(someMessage) } }; }; setInterval(replaceThing, 1000)
以上代碼運(yùn)行時(shí)每次執(zhí)行 replaceThing 方法都會(huì)生成一個(gè)新的對(duì)象,但是之前的對(duì)象沒有釋放導(dǎo)致的內(nèi)存泄漏。這塊涉及到一個(gè)閉包的概念 “同一個(gè)作用域生成的閉包對(duì)象是被該作用域中所有下一級(jí)作用域共同持有的” 因?yàn)槎x的 unused 使用了作用域的 originalThing 變量,因此 replaceThing 這一級(jí)的函數(shù)作用域中的閉包(someMethod)對(duì)象也持有了 originalThing 變量(重點(diǎn):someMethod 的閉包作用域和 unused 的作用域是共享的),之間的引用關(guān)系就是 theThing 引用了 longStr 和 someMethod、someMethod 引用了 originalThing、originalThing 又引用了上次的 theThing,因此形成了鏈?zhǔn)揭谩?/p>
上述代碼來自 Meteor blog An interesting kind of JavaScript memory leak,更多理解還可參考 Node-Interview issues #7 討論
慎將內(nèi)存做為緩存通過內(nèi)存來做緩存這可能是我們想到的最快的實(shí)現(xiàn)方式,另外業(yè)務(wù)中緩存還是很常用的,但是了解了 Node.js 中的內(nèi)存模型和垃圾回收機(jī)制之后在使用的時(shí)候就要謹(jǐn)慎了,為什么呢?緩存中存儲(chǔ)的鍵越多,長(zhǎng)期存活的對(duì)象也就越多,垃圾回收時(shí)將會(huì)對(duì)這些對(duì)對(duì)象做無用功。
以下舉一個(gè)獲取用戶 Token 的例子,memoryStore 對(duì)象會(huì)隨著用戶數(shù)的增加而持續(xù)增長(zhǎng),以下代碼還有一個(gè)問題,當(dāng)你啟動(dòng)多個(gè)進(jìn)程或部署在多臺(tái)機(jī)器會(huì)造成每個(gè)進(jìn)程都會(huì)保存一份,顯然是資源的浪費(fèi),最好是通過 Redis 做共享。
const memoryStore = new Map(); exports.getUserToken = function (key) { const token = memoryStore.get(key); if (token && Date.now() - token.now > 2 * 60) { return token; } const dbToken = db.get(key); memoryStore.set(key, { now: Date.now(), val: dbToken, }); return token; }模塊私有變量?jī)?nèi)存永駐
在加載一個(gè)模塊代碼之前,Node.js 會(huì)使用一個(gè)如下的函數(shù)封裝器將其封裝,保證了頂層的變量(var、const、let)在模塊范圍內(nèi),而不是全局對(duì)象。
這個(gè)時(shí)候就會(huì)形成一個(gè)閉包,在 require 時(shí)會(huì)被加載一次,將 exports 對(duì)象保存于內(nèi)存中,直到進(jìn)程退出才會(huì)回收,這個(gè)將會(huì)導(dǎo)致的是內(nèi)存常駐,所以對(duì)一個(gè)模塊的引用建議僅在頭部引用一次緩存起來,而不是在使用時(shí)每次都加載,否則也會(huì)造成內(nèi)存增加。
(function(exports, require, module, __filename, __dirname) { // 模塊的代碼實(shí)際上在這里 });事件重復(fù)監(jiān)聽
在 Node.js 中對(duì)一個(gè)事件重復(fù)監(jiān)聽則會(huì)報(bào)如下錯(cuò)誤,實(shí)際上使用的 EventEmitter 類,該類包含一個(gè) listeners 數(shù)組,默認(rèn)為 10 個(gè)監(jiān)聽器超出這個(gè)數(shù)則會(huì)報(bào)警如下所示,用于發(fā)現(xiàn)內(nèi)存泄漏,也可以通過 emitter.setMaxListeners() 方法為指定的 EventEmitter 實(shí)例修改限制。
(node:23992) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 connect listeners added. Use emitter.setMaxListeners() to increase limit
Cnode 論欄有篇文章分析了 Socket 重連導(dǎo)致的內(nèi)存泄漏,參考 原生Socket重連策略不恰當(dāng)導(dǎo)致的泄漏,還有 Node.js HTTP 模塊 Keep-Alive 產(chǎn)生的內(nèi)存泄漏,參考 Github Node Issues #714
其它注意事項(xiàng)在使用定時(shí)器 setInterval 時(shí)記的使用對(duì)應(yīng)的 clearInterval 進(jìn)行清除,因?yàn)?setInterval 執(zhí)行完之后會(huì)返回一個(gè)值且不會(huì)自動(dòng)釋放。另外還有 map、filter 等對(duì)數(shù)組進(jìn)行操作,每次操作之后都會(huì)創(chuàng)建一個(gè)新的數(shù)組,將會(huì)占用內(nèi)存,如果單純的遍歷例如 map 可以使用 forEach 代替,這些都是開發(fā)中的一些細(xì)節(jié),但是往往細(xì)節(jié)決定成敗,每一次的內(nèi)存泄漏也都是一次次的不經(jīng)意間造成的。因此,這些點(diǎn)也是需要我們注意的。
console.log(setInterval(function(){}, 1000)) // 返回一個(gè) id 值 [1, 2, 3].filter(item => item % 2 === 0) // [2] [1, 2, 3].map(item => item % 2 === 0) // [false, true, false]內(nèi)存檢測(cè)工具
node-heapdump
heapdump是一個(gè)dumpV8堆信息的工具,node-heapdump
node-profiler
node-profiler 是 alinode 團(tuán)隊(duì)出品的一個(gè) 與node-heapdump 類似的抓取內(nèi)存堆快照的工具,node-profiler
Easy-Monitor
輕量級(jí)的 Node.js 項(xiàng)目?jī)?nèi)核性能監(jiān)控 + 分析工具,https://github.com/hyj1991/easy-monitor
Node.js-Troubleshooting-Guide
Node.js 應(yīng)用線上/線下故障、壓測(cè)問題和性能調(diào)優(yōu)指南手冊(cè),Node.js-Troubleshooting-Guide
alinode
Node.js 性能平臺(tái)(Node.js Performance Platform)是面向中大型 Node.js 應(yīng)用提供 性能監(jiān)控、安全提醒、故障排查、性能優(yōu)化等服務(wù)的整體性解決方案。alinode
閱讀推薦Node.js Garbage Collection Explained
A tour of V8: Garbage Collection 中文版 V8 之旅: 垃圾回收器
Memory Management Reference.
深入淺出 Node.js
如何分析 Node.js 中的內(nèi)存泄漏
公眾號(hào) “Nodejs技術(shù)?!?,專注于 Node.js 技術(shù)棧的分享
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/105253.html
摘要:的內(nèi)存限制和垃圾回收機(jī)制內(nèi)存限制內(nèi)存限制一般的后端語言開發(fā)中,在基本的內(nèi)存使用是沒有限制的。的內(nèi)存分代目前沒有一種垃圾自動(dòng)回收算法適用于所有場(chǎng)景,所以的內(nèi)部采用的其實(shí)是兩種垃圾回收算法。 前言 從前端思維轉(zhuǎn)變到后端, 有一個(gè)很重要的點(diǎn)就是內(nèi)存管理。以前寫前端因?yàn)橹皇窃跒g覽器上運(yùn)行, 所以對(duì)于內(nèi)存管理一般不怎么需要上心, 但是在服務(wù)器端, 則需要斤斤計(jì)較內(nèi)存。 V8的內(nèi)存限制和垃圾回收機(jī)...
摘要:正好最近在學(xué)習(xí)的各種實(shí)現(xiàn)原理,在這里斗膽翻譯一篇垃圾回收機(jī)制原文鏈接。自動(dòng)管理的機(jī)制中,通常都會(huì)包含垃圾回收機(jī)制。二垃圾回收機(jī)制的概念垃圾回收,是一種自動(dòng)管理應(yīng)用程序所占內(nèi)存的機(jī)制,簡(jiǎn)稱方便起見,本文均采用此簡(jiǎn)寫。 最近關(guān)注了一個(gè)國(guó)外技術(shù)博客RisingStack里面有很多高質(zhì)量,且對(duì)新手也很friendly的文章。正好最近在學(xué)習(xí)Node.js的各種實(shí)現(xiàn)原理,在這里斗膽翻譯一篇Node...
摘要:新生代的對(duì)象為存活時(shí)間較短的對(duì)象,老生代中的對(duì)象為存活時(shí)間較長(zhǎng)或常駐內(nèi)存的對(duì)象。分別對(duì)新生代和老生代使用不同的垃圾回收算法來提升垃圾回收的效率。如果指向老生代我們就不必考慮它了。 這篇文章的所有內(nèi)容均來自 樸靈的《深入淺出Node.js》及A tour of V8:Garbage Collection,后者還有中文翻譯版V8 之旅: 垃圾回收器,我在這里只是做了個(gè)記錄和結(jié)合 垃圾回收...
摘要:關(guān)鍵是釋放內(nèi)存這一步,各種語言都有自己的垃圾回收簡(jiǎn)稱機(jī)制。用的是這種,在字末位進(jìn)行標(biāo)識(shí),為指針。對(duì)于而言,最初的垃圾回收機(jī)制,是基于引用計(jì)次來做的。老生代的垃圾回收,分兩個(gè)階段標(biāo)記清理有和這兩種方式。 不管是高級(jí)語言,還是低級(jí)語言。內(nèi)存的管理都是: 分配內(nèi)存 使用內(nèi)存(讀或?qū)懀?釋放內(nèi)存 前兩步,大家都沒有太大異議。關(guān)鍵是釋放內(nèi)存這一步,各種語言都有自己的垃圾回收(garbage ...
摘要:內(nèi)存管理具有垃圾自動(dòng)回收機(jī)制簡(jiǎn)稱。標(biāo)記清除標(biāo)記清除是目前大部分引擎使用的判斷方式,通過標(biāo)記變量的狀態(tài)來確定是否可被回收。被標(biāo)記,進(jìn)入環(huán)境被標(biāo)記,進(jìn)入環(huán)境執(zhí)行完畢之后被標(biāo)記,離開環(huán)境引用計(jì)數(shù)引擎維護(hù)一張引用表,保存內(nèi)存中所有的資源的引用次數(shù)。 JavaScript 內(nèi)存管理 JavaScript 具有垃圾自動(dòng)回收機(jī)制(Garbage Collection)簡(jiǎn)稱 GC。垃圾回收機(jī)制會(huì)中斷整...
閱讀 2493·2021-10-09 09:59
閱讀 2274·2021-09-23 11:30
閱讀 2663·2019-08-30 15:56
閱讀 1207·2019-08-30 14:00
閱讀 3006·2019-08-29 12:37
閱讀 1328·2019-08-28 18:16
閱讀 1714·2019-08-27 10:56
閱讀 1087·2019-08-26 17:23