瘋狂的技術宅 前端先鋒 2前端
翻譯:瘋狂的技術宅
做者:Giovanny Gongora
來源:nodesource
正文共:3955 字
預計閱讀時間:10分鐘node
一直以來,跟蹤 Node.js 的內存泄漏是一個反覆出現的話題,人們始終但願對其複雜性和緣由瞭解更多。json
並不是全部的內存泄漏都顯而易見。可是,一旦咱們肯定了其模式,就必須在內存使用率,內存中保存的對象和響應時間之間尋找關聯。在檢查對象時,應該根據本身所用的框架或技術(例如服務器端渲染),研究收集了多少對象,以及它們是否正常。但願在完成本文結束以後,你將可以理解並尋找一種策略來調試 Node.js 程序的內存消耗。服務器
JavaScript 是一種垃圾回收語言,而 Google 的 V8 最初是爲 Google Chrome 建立的JavaScript引擎,在許多狀況下均可以用做獨立的運行時。Node.js 中垃圾收集器的兩個重要操做是:markdown
V8 JavaScript 引擎會自動分配和取消分配 Node.js 進程使用的全部內存。讓咱們看看實際狀況是怎樣的。閉包
若是你將內存視爲一個樹結構,那麼能夠想象 V8 從「根節點」開始保存程序中全部的變量。這多是你的 window 對象,也多是 Node.js 模塊中的全局對象,一般稱爲控制者。須要牢記的一點是,你沒法對怎樣取消分配「根」節點進行控制。
app
接下來,你將找到一個 Object 節點,一般被稱爲葉子(沒有子引用的節點)。最後 JavaScript 中有 4 種數據類型:布爾值,字符串,數字和對象。框架
V8 將遍歷該樹並嘗試識別沒法從「根」節點訪問的數據組。若是沒法從「根」節點訪問該數據,則 V8 假定再也不使用該數據,並釋放內存。請記住:要肯定某個對象是否處於活動狀態,須要檢查是否可經過被定義爲活動對象的某個指針鏈到達;其餘全部的狀況,例如沒法從根節點訪問,或沒法被根節點或另外一個活動對象引用的對象,都會被視爲垃圾。dom
簡而言之,垃圾收集器有兩個主要任務:ide
V8 使用相似於 Java 虛擬機的方案,並將內存劃分爲多個段。實現這種包裝方案的東西被稱爲「駐留集」,它是指在 RAM 中駐留的進程所佔用的內存部分。
在駐留集中,你會發現:
堆: 專門用於存儲引用類型(如對象、字符串和閉包)的內存段。
還有重要的兩點要記住:
對象的保留大小:當刪除對象及其依賴對象時,被釋放的內存大小
Node.js 有一個對象,以字節爲單位描述 Node.js 進程的內存使用狀況。在對象內部,你會發現:
Chrome DevTools 是一個很棒的工具,可用於經過遠程調試來診斷 Node.js 程序中的內存泄漏。也有其餘爲你提供相似功能的工具。可是,你須要記住,概要分析是一項繁重的 CPU 任務,可能會對你的程序產生負面影響,必定要注意這一點!
咱們將要介紹的 Node.js 程序是一個簡單的 HTTP API Server,它具備多個端點,向使用該服務的人返回不一樣的信息。你能夠克隆這個程序的repository。
1const http = require('http') 2 3const leak = [] 4 5function requestListener(req, res) { 6 7 if (req.url === '/now') { 8 let resp = JSON.stringify({ now: new Date() }) 9 leak.push(JSON.parse(resp)) 10 res.writeHead(200, { 'Content-Type': 'application/json' }) 11 res.write(resp) 12 res.end() 13 } else if (req.url === '/getSushi') { 14 function importantMath() { 15 let endTime = Date.now() + (5 * 1000); 16 while (Date.now() < endTime) { 17 Math.random(); 18 } 19 } 20 21 function theSushiTable() { 22 return new Promise(resolve => { 23 resolve('