JS中堆棧內存的釋放問題

開闢的堆內存或者造成的上下文(進棧執行=>棧內存)是越多越好,仍是越少越好?javascript

  • 確定是越少越好,由於計算機的內存是固定的,咱們全部開闢的內存都在佔用計算機的資源,當計算機內消耗存過多,性能也就愈來愈卡(直接致使咱們的產品運行變慢)

思惟導圖

函數執行就會造成棧內存(從內存中分配的一塊空間),若是內存都不銷燬釋放,很容易就會致使棧內存溢出(內存爆滿,電腦就卡死了), => 因此JS中一個重要的性能優化點:減小內存的使用java

  • =>釋放堆內存
  • =>釋放棧內存(也就是讓進棧執行的上下文,儘量出棧釋放)

1、堆內存(HEAP)和 棧內存(STACK)

一、堆內存(HEAP)

  • 堆內存是用來存儲引用數據類型值的
    • (例如:建立函數和建立對象,就是開闢一個堆內存,把代碼字符串或者鍵值對存儲到堆內存中的)

二、棧內存(STACK)

  • 棧內存是用來執行代碼和存儲基本類型值的(建立的變量也存棧裏面了),
    • 不只全局代碼執行(EC(G)全局執行上下文),
    • 並且函數執行(EC(X)私有上下文),最後也都會進棧執行的
    • 基於ES6中的let/const造成的塊做用域也是棧內存

2、瀏覽器經常使用的垃圾回收機制(內存釋放機制):

一、 查找引用方式(weblit內核)

瀏覽器有自動回收垃圾的機制,按期間隔某段時間,把全部沒有被佔用的內存回收釋放(這種垃圾回收機制,比其它語言要完善一些)web

-1).不會銷燬的狀況:

  • 建立一個堆(16進制地址):
    • 若是有變量或者其它東西存儲了堆內存的地址,則當前堆內存被視爲佔用,也就不能釋放銷燬
  • 上下文進棧執行;
    • 若是當前上下文中的某些內容(通常也是當前上下文中建立的堆)被上下文之外的變量或者其它事務所佔用,那麼當前上下文就不能出棧釋放(可是通常狀況下,上下文中代碼執行完,上下文本身就出棧釋放了)

-2).堆內存釋放

若是堆內存用完後,咱們想去手動釋放它,則取消全部的佔用:賦值爲NULL(NULL是空對象指針,也就是不指向任何的堆內存)瀏覽器

//=>建立一個引用類型值,就會產生一個堆內存
//若是當前建立的堆內存不被其它東西所佔用了(瀏覽器會在空閒的時候,查找每個內存的引用情況,不被佔用的都會給回收釋放掉),則會釋放
let obj = {
    name : 'xiaozhima'
};
let oop = obj;
//此時obj和oop都佔用着對象的堆內存,想要釋放堆內存,須要手動解除變量和值的關聯(null:空對象指針)
obj = null;
oop = null;
複製代碼

-3).棧內存釋放

棧內存:性能優化

  • 打開瀏覽器造成的全局做用域是棧內存
  • 手動執行函數造成的私有做用域是棧內存
  • 基於ES6中的let/const造成的塊做用域也是棧內存
  • ......

棧內存銷燬:bash

  • 全局棧內存:關掉頁面的時候纔會銷燬
  • 私有棧內存:
    • 1.通常狀況下,函數只要執行完成,造成的私有棧內存就會被銷燬釋放掉(排除出現無限極遞歸、出現死循環的模式)
    • 2.可是一旦棧內存中的某個東西(通常都是堆地址)被私有做用域之外的事物給佔用了,則當前私有棧內存不能當即被釋放銷燬(特色:私有做用域中的私有變量等信息也保留下來了=>這種函數執行造成不能被釋放的私有棧內存,也叫作閉包)
function fn(){
    //...
}
fn(); //=>函數執行造成棧內存,執行完成棧內存銷燬
     
function X(){
    return function(){
        //...
    }
}
let f=X(); //=>f佔用了X執行造成的棧內存中的一個東西(返回小函數對應的堆),則X執行造成的棧內存不能被釋放了
複製代碼

二、內存計數器方式(Trident內核)

當前內存被其它東西引用了,則給堆計數1(累加計數),取消佔用後,則減1,當減到零以後,瀏覽器就能夠把它釋放了閉包

3、練習題

1.輸出結果

var i = 5;
function fn(i) {
	return function (n) {
		console.log(n + (++i));
	}
}
var f = fn(1);
f(2);
fn(3)(4);
fn(5)(6);
f(7);
console.log(i);
複製代碼

2.輸出結果

let x = 5;
function fn(x) {
    return function(y) {
        console.log(y + (++x));
    }
}
let f = fn(6);
f(7);
fn(8)(9);
f(10);
console.log(x);
複製代碼

3.輸出結果

let a=0,
    b=0;
function A(a){
    A=function(b){
        alert(a+b++);
    };
    alert(a++);
}
A(1);
A(2);
複製代碼

4.輸出結果

var n=0; 
function a(){
    var n=10; 
    function b(){
        n++; 
        console.log(n); 
    }
    b();
    return b; 
}
var c=a();
c(); 
console.log(n);
複製代碼

5.輸出結果

var test = (function(i){
    return function(){
        alert(i*=2);
    }
})(2);
test(5);
複製代碼

相關文章
相關標籤/搜索