摘要:引擎對堆內存中的對象進行分代管理新生代存活周期較短的對象,如臨時變量字符串等。內存泄漏對于持續運行的服務進程,必須及時釋放不再用到的內存。
(關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導)
本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第4天。
本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃,點擊查看前端進階的破冰之旅
本期推薦文章JavaScript 內存機制 ,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。
推薦理由面試中,如果能和面試官聊到內存機制,肯定會給自己加分很多。在JS中大家不是很在意垃圾回收,認為系統會做好回收工作,但是這并不是說不會有內存泄漏的情況,今天的文章正好給你查漏補缺。
閱讀筆記JS內存空間分為棧(stack)、堆(heap)、池(一般也會歸類為棧中)。 其中棧存放變量,堆存放復雜對象,池存放常量,所以也叫常量池。
昨天文章介紹了堆和棧,小結一下,【進階1-3期】JavaScript深入之內存空間詳細圖解
基本類型:--> 棧內存(不包含閉包中的變量)
引用類型:--> 堆內存
今日補充一個知識點,就是閉包中的變量并不保存中棧內存中,而是保存在堆內存中,這也就解釋了函數之后之后為什么閉包還能引用到函數內的變量。
function A() { let a = 1 function B() { console.log(a) } return B }
閉包的簡單定義是:函數 A 返回了一個函數 B,并且函數 B 中使用了函數 A 的變量,函數 B 就被稱為閉包。
函數 A 彈出調用棧后,函數 A 中的變量這時候是存儲在堆上的,所以函數B依舊能引用到函數A中的變量。現在的 JS 引擎可以通過逃逸分析辨別出哪些變量需要存儲在堆上,哪些需要存儲在棧上。
閉包的介紹點到為止,【進階2期】 作用域閉包會詳細介紹,敬請期待。
今天文章的重點是內存回收和內存泄漏。
內存回收JavaScript有自動垃圾收集機制,垃圾收集器會每隔一段時間就執行一次釋放操作,找出那些不再繼續使用的值,然后釋放其占用的內存。
局部變量和全局變量的銷毀
局部變量:局部作用域中,當函數執行完畢,局部變量也就沒有存在的必要了,因此垃圾收集器很容易做出判斷并回收。
全局變量:全局變量什么時候需要自動釋放內存空間則很難判斷,所以在開發中盡量避免使用全局變量。
以Google的V8引擎為例,V8引擎中所有的JS對象都是通過堆來進行內存分配的
初始分配:當聲明變量并賦值時,V8引擎就會在堆內存中分配給這個變量。
繼續申請:當已申請的內存不足以存儲這個變量時,V8引擎就會繼續申請內存,直到堆的大小達到了V8引擎的內存上限為止。
V8引擎對堆內存中的JS對象進行分代管理
新生代:存活周期較短的JS對象,如臨時變量、字符串等。
老生代:經過多次垃圾回收仍然存活,存活周期較長的對象,如主控制器、服務器對象等。
垃圾回收算法對垃圾回收算法來說,核心思想就是如何判斷內存已經不再使用,常用垃圾回收算法有下面兩種。
引用計數(現代瀏覽器不再使用)
標記清除(常用)
引用計數算法定義“內存不再使用”的標準很簡單,就是看一個對象是否有指向它的引用。如果沒有其他對象指向它了,說明該對象已經不再需要了。
// 創建一個對象person,他有兩個指向屬性age和name的引用 var person = { age: 12, name: "aaaa" }; person.name = null; // 雖然name設置為null,但因為person對象還有指向name的引用,因此name不會回收 var p = person; person = 1; //原來的person對象被賦值為1,但因為有新引用p指向原person對象,因此它不會被回收 p = null; //原person對象已經沒有引用,很快會被回收
引用計數有一個致命的問題,那就是循環引用
如果兩個對象相互引用,盡管他們已不再使用,但是垃圾回收器不會進行回收,最終可能會導致內存泄露。
function cycle() { var o1 = {}; var o2 = {}; o1.a = o2; o2.a = o1; return "cycle reference!" } cycle();
cycle函數執行完成之后,對象o1和o2實際上已經不再需要了,但根據引用計數的原則,他們之間的相互引用依然存在,因此這部分內存不會被回收。所以現代瀏覽器不再使用這個算法。
但是IE依舊使用。
var div = document.createElement("div"); div.onclick = function() { console.log("click"); };
上面的寫法很常見,但是上面的例子就是一個循環引用。
變量div有事件處理函數的引用,同時事件處理函數也有div的引用,因為div變量可在函數內被訪問,所以循環引用就出現了。
標記清除算法將“不再使用的對象”定義為“無法到達的對象”。即從根部(在JS中就是全局對象)出發定時掃描內存中的對象,凡是能從根部到達的對象,保留。那些從根部出發無法觸及到的對象被標記為不再使用,稍后進行回收。
無法觸及的對象包含了沒有引用的對象這個概念,但反之未必成立。
所以上面的例子就可以正確被垃圾回收處理了。
所以現在對于主流瀏覽器來說,只需要切斷需要回收的對象與根部的聯系。最常見的內存泄露一般都與DOM元素綁定有關:
email.message = document.createElement(“div”); displayList.appendChild(email.message); // 稍后從displayList中清除DOM元素 displayList.removeAllChildren();
上面代碼中,div元素已經從DOM樹中清除,但是該div元素還綁定在email對象中,所以如果email對象存在,那么該div元素就會一直保存在內存中。
內存泄漏對于持續運行的服務進程(daemon),必須及時釋放不再用到的內存。否則,內存占用越來越高,輕則影響系統性能,重則導致進程崩潰。 對于不再用到的內存,沒有及時釋放,就叫做內存泄漏(memory leak)
內存泄漏識別方法打開開發者工具,選擇 Memory
在右側的Select profiling type字段里面勾選 timeline
點擊左上角的錄制按鈕。
在頁面上進行各種操作,模擬用戶的使用情況。
一段時間后,點擊左上角的 stop 按鈕,面板上就會顯示這段時間的內存占用情況。
使用 Node 提供的 process.memoryUsage 方法。
console.log(process.memoryUsage()); // 輸出 { rss: 27709440, // resident set size,所有內存占用,包括指令區和堆棧 heapTotal: 5685248, // "堆"占用的內存,包括用到的和沒用到的 heapUsed: 3449392, // 用到的堆的部分 external: 8772 // V8 引擎內部的 C++ 對象占用的內存 }
判斷內存泄漏,以heapUsed字段為準。
詳細的JS內存分析將在【進階20期】性能優化詳細介紹,敬請期待。
WeakMapES6 新出的兩種數據結構:WeakSet 和 WeakMap,表示這是弱引用,它們對于值的引用都是不計入垃圾回收機制的。
const wm = new WeakMap(); const element = document.getElementById("example"); wm.set(element, "some information"); wm.get(element) // "some information"
先新建一個 Weakmap 實例,然后將一個 DOM 節點作為鍵名存入該實例,并將一些附加信息作為鍵值,一起存放在 WeakMap 里面。這時,WeakMap 里面對element的引用就是弱引用,不會被計入垃圾回收機制。
昨日思考題解答昨天文章留了一道思考題,群里討論很熱烈,大家應該都知道原理了,現在來簡單解答下。
var a = {n: 1}; var b = a; a.x = a = {n: 2}; a.x // --> undefined b.x // --> {n: 2}
答案已經寫上面了,這道題的關鍵在于
1、優先級。.的優先級高于=,所以先執行a.x,堆內存中的{n: 1}就會變成{n: 1, x: undefined},改變之后相應的b.x也變化了,因為指向的是同一個對象。
2、賦值操作是從右到左,所以先執行a = {n: 2},a的引用就被改變了,然后這個返回值又賦值給了a.x,需要注意的是這時候a.x是第一步中的{n: 1, x: undefined}那個對象,其實就是b.x,相當于b.x = {n: 2}
今日份思考題問題一:
從內存來看 null 和 undefined 本質的區別是什么?
問題二:
ES6語法中的 const 聲明一個只讀的常量,那為什么下面可以修改const的值?
const foo = {}; foo = {}; // TypeError: "foo" is read-only foo.prop = 123; foo.prop // 123
問題三:
哪些情況下容易產生內存泄漏?
參考JavaScript 內存機制往期文章查看MDN之運算符優先級
由ES規范學JavaScript(二):深入理解“連等賦值”問題
InterviewMap
【進階1-1期】理解JavaScript 中的執行上下文和執行棧
【進階1-2期】JavaScript深入之執行上下文棧和變量對象
【進階1-3期】JavaScript深入之內存空間詳細圖解
【進階1-4期】JavaScript深入之帶你走進內存機制制
【進階1-5期】JavaScript深入之4類常見內存泄漏及如何避免
【進階2-1期】深入淺出圖解作用域鏈和閉包
每周計劃安排每周面試重難點計劃如下,如有修改會通知大家。每周一期,為期半年,準備明年跳槽的小伙伴們可以把本公眾號置頂了。
【進階1期】 調用堆棧
【進階2期】 作用域閉包
【進階3期】 this全面解析
【進階4期】 深淺拷貝原理
【進階5期】 原型Prototype
【進階6期】 高階函數
【進階7期】 事件機制
【進階8期】 Event Loop原理
【進階9期】 Promise原理
【進階10期】Async/Await原理
【進階11期】防抖/節流原理
【進階12期】模塊化詳解
【進階13期】ES6重難點
【進階14期】計算機網絡概述
【進階15期】瀏覽器渲染原理
【進階16期】webpack配置
【進階17期】webpack原理
【進階18期】前端監控
【進階19期】跨域和安全
【進階20期】性能優化
【進階21期】VirtualDom原理
【進階22期】Diff算法
【進階23期】MVVM雙向綁定
【進階24期】Vuex原理
【進階25期】Redux原理
【進階26期】路由原理
【進階27期】VueRouter源碼解析
【進階28期】ReactRouter源碼解析
交流本人Github鏈接如下,歡迎各位Star
http://github.com/yygmind/blog
我是木易楊,網易高級前端工程師,跟著我每周重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!
如果你想加群討論每期面試知識點,公眾號回復[加群]即可
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99555.html
摘要:本期推薦文章類內存泄漏及如何避免,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。四種常見的內存泄漏劃重點這是個考點意外的全局變量未定義的變量會在全局對象創建一個新變量,如下。因為老版本的是無法檢測節點與代碼之間的循環引用,會導致內存泄漏。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題...
摘要:進階期理解中的執行上下文和執行棧進階期深入之執行上下文棧和變量對象但是今天補充一個知識點某些情況下,調用堆棧中函數調用的數量超出了調用堆棧的實際大小,瀏覽器會拋出一個錯誤終止運行。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第3天。 本計劃一共28期,每期重點攻...
摘要:首次運行代碼時,會創建一個全局執行上下文并到當前的執行棧中。執行上下文的創建執行上下文分兩個階段創建創建階段執行階段創建階段確定的值,也被稱為。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,,今天是第一天 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數,也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:閉包面試題解由于作用域鏈機制的影響,閉包只能取得內部函數的最后一個值,這引起的一個副作用就是如果內部函數在一個循環中,那么變量的值始終為最后一個值。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第8天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了...
閱讀 3735·2023-01-11 11:02
閱讀 4244·2023-01-11 11:02
閱讀 3050·2023-01-11 11:02
閱讀 5180·2023-01-11 11:02
閱讀 4737·2023-01-11 11:02
閱讀 5534·2023-01-11 11:02
閱讀 5313·2023-01-11 11:02
閱讀 3990·2023-01-11 11:02