如果你也喜歡分享,歡迎加入我們:QQ group:164858883
內存策略:堆內存和棧內存
棧內存:在函數中定義的一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配。當在一段代碼塊中定義一個變量時,系統就在棧中為這個變量分配內存空間,當超過變量的作用域后,系統會自動釋放掉為該變量分配的內存空間,該內存空間可以立刻被另作他用。
堆內存:堆內存用於存放由new創建的對象和數組。在堆中分配的內存,由虛擬機自動垃圾回收器來管理。在堆中產生了一個數組或者對象后,還可以在棧中定義一個特殊的變量,這個變量的取值等於數組或者對象在堆內存中的首地址,在棧中的這個特殊的變量就變成了數組或者對象的引用變量,以后就可以在程序中使用棧內存中的引用變量來訪問堆中的數組或者對象,引用變量相當於為數組或者對象起的一個別名,或者代號。
引用變量是普通變量,定義時在棧中分配內存,引用變量在程序運行到作用域外釋放。而數組&對象本身在堆中分配,即使程序運行到使用new產生數組和對象的語句所在地代碼塊之外,數組和對象本身占用的堆內存也不會被釋放,數組和對象在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,但是仍然占着內存,在隨后的一個不確定的時間被垃圾回收器釋放掉。
JAVASCRIPT的內存回收機制
以Google的V8引擎為例,在V8引擎中所有的JAVASCRIPT對象都是通過堆來進行內存分配的。當我們在代碼中聲明變量並賦值時,V8引擎就會在堆內存中分配一部分給這個變量。如果已申請的內存不足以存儲這個變量時,V8引擎就會繼續申請內存,直到堆的大小達到了V8引擎的內存上限為止(默認情況下,V8引擎的堆內存的大小上限在64位系統中為1464MB,在32位系統中則為732MB)。
另外,V8引擎對堆內存中的JAVASCRIPT對象進行分代管理。新生代:新生代即存活周期較短的JAVASCRIPT對象,如臨時變量、字符串等;
老生代:老生代則為經過多次垃圾回收仍然存活,存活周期較長的對象,如主控制器、服務器對象等。
垃圾回收算法
垃圾回收算法一直是編程語言的研發中是否重要的一環,而V8引擎所使用的垃圾回收算法主要有以下幾種。
Scavange算法:通過復制的方式進行內存空間管理,主要用於新生代的內存空間;
Mark-Sweep算法和Mark-Compact算法:通過標記來對堆內存進行整理和回收,主要用於老生代對象的檢查和回收。
對象進行回收。
引用
當函數執行完畢時,在函數內部所聲明的對象不一定就會被銷毀。
引用(Reference)是JAVASCRIPT編程中十分重要的一個機制。
是指代碼對對象的訪問這一抽象關系,它與C/C++的指針有點相似,但並非同物。引用同時也是JAVASCRIPT引擎在進行垃圾回收中最關鍵的一個機制。
var val = 'hello world'; function foo() { return function() { return val; }; } global.bar = foo();
當代碼執行完畢時,對象val和bar()並沒有被回收釋放,JAVASCRIPT代碼中,每個變量作為單獨一行而不做任何操作,JAVASCRIPT引擎都會認為這是對對象的訪問行為,存在了對對象的引用。為了保證垃圾回收的行為不影響程序邏輯的運行,JAVASCRIPT引擎不會把正在使用的對象進行回收。所以判斷對象是否正在使用中的標准,就是是否仍然存在對該對象的引用。
JAVASCRIPT的引用是可以進行轉移的,那么就有可能出現某些引用被帶到了全局作用域,但事實上在業務邏輯里已經不需要對其進行訪問了,這個時候就應該被回收,但是JAVASCRIPT引擎仍會認為程序仍然需要它。
IE下閉包引起跨頁面內存泄露
JAVASCRIPT的內存泄露處理
1、給DOM對象添加的屬性是一個對象的引用。
var MyObject = {}; document.getElementByIdx_x('myDiv').myProp = MyObject;
解決方法:在window.onunload事件中寫上:
document.getElementByIdx_x('myDiv').myProp = null;
2、DOM對象與JS對象相互引用。
function Encapsulator(element) { this.elementReference = element; element.myProp = this; } new Encapsulator(document.getElementByIdx_x('myDiv'));
解決方法:在onunload事件中寫上:
document.getElementByIdx_x('myDiv').myProp = null;
3、給DOM對象用attachEvent綁定事件。
function doClick() {} element.attachEvent("onclick", doClick);
解決方法:在onunload事件中寫上:
element.detachEvent('onclick', doClick);
4、從外到內執行appendChild。這時即使調用removeChild也無法釋放。
var parentDiv = document.createElement_x("div"); var childDiv = document.createElement_x("div"); document.body.appendChild(parentDiv); parentDiv.appendChild(childDiv);
解決方法:從內到外執行appendChild:
var parentDiv = document.createElement_x("div"); var childDiv = document.createElement_x("div"); parentDiv.appendChild(childDiv); document.body.appendChild(parentDiv);
5、反復重寫同一個屬性會造成內存大量占用(但關閉IE后內存會被釋放)。
for(i = 0; i < 5000; i++) { hostElement.text = "asdfasdfasdf"; }
這種方式相當於定義了5000個屬性,解決方法:無。
內存不是緩存。
不要輕易將內存當作緩存使用。
如果是很重要的資源,請不要直接放在內存中,或者制定過期機制,自動銷毀過期緩存。
CollectGarbage。
CollectGarbage是IE的一個特有屬性,用於釋放內存的使用方法,將該變量或引用對象設置為null或delete然后在進行釋放動作,在做CollectGarbage前,要必需清楚的兩個必備條件:(引用)。
1、一個對象在其生存的上下文環境之外,即會失效。
2、一個全局的對象在沒有被執用(引用)的情況下,即會失效