js閉包一定引發內存泄漏嗎

什麼是內存泄漏

像c,c++這種語言,有個free函數,用來釋放動態分配的內存.若是某個或某些動態分配的變量沒有了做用,而且佔用的內存很大,足以影響整個程序的運行.這就叫內存泄漏.同理,像js,java這種語言,由v8和jvm等來幫助管理這部份內存.他們管理的時候都不會釋放你有可能用到的內存.
如下以js爲例.v8並不知道你須要用到哪些對象.因此他只能經過一些條件來判斷出你絕對不會使用的對象.好比若是一個對象已經沒有了引用,那你確定就沒法用js來操做這個對象了,v8就認爲這個對象佔用的內存是能夠釋放的了.但他並不必定會當即釋放,gc(釋放垃圾內存)是有性能損耗的.全部v8的gc也是有必定算法的.假設你有這樣一段代碼:
let arr = new Array(1000000)
即便你下面不會使用到arr,v8也絕對不會釋放掉arr佔用的內存,由於還有arr這個引用.怎麼來證實這一點呢.前面說過v8的gc時機是有必定的算法的.不過node有一個global.gc()方法,可以全局gc,可是須要--expose-gc參數來執行node進程.node還有一個方法,process.memoryUsage()可以查看這個node進程的內存佔用狀況.java

輸入圖片說明

代碼1中演示了這兩個方法的使用.能夠看出第一次強制全局gc,並無將這個1000000長度空數組佔用的內存釋放掉.內存從最開始的5M上升到了12M.將這個數組的引用去掉後,再次gc,便能釋放這部份內存.
那麼問題來了,假設我寫了段代碼,並無將arr置爲null,而且之後也不會使用這個arr.那個人代碼算是內存泄漏了嗎?多是吧,那個人arr所引用的數組長度不是1000000了,而是0.arr=[].那我這還算是內存泄漏嗎?我以爲不是.感受內存泄漏是個辯證的見解吧,若是某個不會使用的對象,咱們在代碼裏把他寫成了不能讓v8釋放,這就構成了內存泄漏,我以爲誰都寫過內存泄漏的代碼.要是有一個對象不用了,我就要將他的全部引用置爲空.那我還要v8的垃圾回收作什麼,我置位空,v8也不見得回收他,倒不如用c語言的free好了.
因此我以爲只有沒必要要的大內存,因爲代碼問題,形成v8不能回收.影響了程序的性能,這才叫內存泄漏.而本文要討論的實際是: js閉包,一定會引發部份內存不能釋放嗎?node

什麼是js閉包

學過js的人應該都瞭解,js的變量做用域.外部做用域,不能訪問內部做用域的變量.反過來能夠.而閉包,引用樸靈大大的話,即是在js中,實現外部做用域訪問內部做用域中變量的方法叫作閉包.
輸入圖片說明 在代碼2中,內部引用inLead並不能在外部直接訪問,可是getInLeadFn做用域裏能夠訪問,包括返回的匿名函數.將這個匿名函數經過執行getInLeadFn引用到外部做用域,即可以間接訪問inLead.c++

js閉包會引發內存不能釋放嗎?

記得剛面試的時候,就有面試官問過我,閉包的危害.當時本身沒有回答上來,面試官當時告訴我,會引發內存泄漏.當時本身對內存的概念不太關注.就這樣記住了,到後來,愈來愈懷疑這句話.百度,網上也有的言論是這樣說的.仍是實踐出真知.
輸入圖片說明 寫完整個閉包,能夠看出,內存從5M到了14M,gc也還剩13M.可是隻要將outLeadFn置位null,即將內部做用域的函數引用去掉,再gc,便能釋放內存.
有沒有看到,這和代碼1是相似的.因此我以爲js閉包,只不過是把內部做用域的對象延伸到了外部罷了,就像外部做用域的對象有引用內存不能gc,經過js閉包獲得的內部對象若是有引用,也不能gc.
有人會說,inLead這個引用還在指向這個數組呢.引用的內存分配在棧上,對象的內存分配在堆上.當函數執行完以後,函數棧上的內存即可以釋放了.當fn這個函數執行完以後,fn裏的inLead便被銷燬了,不須要等待gc.這也是爲何在外層做用域不能再找到inLead了.面試

總結

**js閉包,不會引起內存不能釋放,更不會引發內存泄漏.只不過是把內部做用域的對象延伸到了外部罷了,想要經過gc釋放這個對象的內存,只須要將引用去掉便可. **有問題,但願指出,謝謝!算法

相關文章
相關標籤/搜索