JavaScript內(nèi)存模型是指程序在執(zhí)行的時候,如何動態(tài)地分配內(nèi)存,如何管理內(nèi)存空間以及內(nèi)存的回收和釋放。
JavaScript中的變量分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型。基本數(shù)據(jù)類型在內(nèi)存中直接存儲值,例如數(shù)字、字符串和布爾值。而引用數(shù)據(jù)類型則是存儲在堆內(nèi)存中,包括對象、數(shù)組和函數(shù)等復(fù)雜的數(shù)據(jù)類型。在堆內(nèi)存中,每個對象都有一個唯一的地址指針,JavaScript通過地址指針來訪問并操作對象數(shù)據(jù)。
// 值類型的存儲特點 var a = 1; var b = a; b = 2; console.log(a); // 1 console.log(b); // 2 // 引用類型的存儲特點 var arr1 = [1, 2, 3]; var arr2 = arr1; arr2.push(4); console.log(arr1); // [1, 2, 3, 4] console.log(arr2); // [1, 2, 3, 4]
在JavaScript中,所有引用變量都是按照值傳遞的,因此,復(fù)制一個引用類型變量時,復(fù)制的是地址指針而不是實際的數(shù)據(jù)。由于這種引用的方式,不同的變量引用同一個對象時,修改其中一個變量就會影響到其他變量。
在JavaScript中,通過var、let或const聲明的變量都是存儲在棧內(nèi)存中。當(dāng)程序在執(zhí)行時,會為每個變量在棧內(nèi)存中分配一段固定大小的空間,可以通過變量名直接訪問該空間。而堆內(nèi)存則是為動態(tài)分配的引用類型數(shù)據(jù)提供的存儲空間。JavaScript引擎通過垃圾回收機制來釋放不再使用的對象內(nèi)存,以便重新分配內(nèi)存空間。
function getUser() { var user = { name: 'Tom', age: 20 }; return user; } var user1 = getUser(); var user2 = getUser(); console.log(user1 === user2); // false
在函數(shù)調(diào)用時,當(dāng)函數(shù)返回一個引用類型的數(shù)據(jù)時,JavaScript會創(chuàng)建一個新的對象并把對象的地址指針復(fù)制給返回的變量。每次調(diào)用函數(shù)時都會創(chuàng)建一個新的對象,即使兩次調(diào)用函數(shù)返回的數(shù)據(jù)一模一樣,它們在內(nèi)存中的地址指針也是不同的。
JavaScript中的垃圾回收機制是一種自動的內(nèi)存管理系統(tǒng),可以在應(yīng)用程序運行時自動識別和釋放不再使用的對象,節(jié)約內(nèi)存資源。垃圾回收的策略是標(biāo)記清除,JavaScript引擎會周期性地掃描內(nèi)存中的變量,標(biāo)記不再使用的變量,然后清除標(biāo)記過的變量所占用的內(nèi)存空間。
在JavaScript中,如果一個對象不再有任何引用變量指向它,那么該對象就可以被垃圾回收器自動回收。但是,在循環(huán)中引用的對象,或者在全局作用域中的變量對象,可能會導(dǎo)致內(nèi)存泄漏,因為它們的引用關(guān)系沒有被切斷。
// 閉包引起的內(nèi)存泄漏 function outer() { var greeting = 'Hello'; function inner() { setTimeout(function() { console.log(greeting); }, 1000); } return inner; } var greet = outer(); greet(); // 'Hello' // 1秒鐘后,inner函數(shù)執(zhí)行完成后,由于greeting變量的作用域鏈引用,greeting所占據(jù)的內(nèi)存空間不會被垃圾回收機制回收,造成了內(nèi)存泄漏
JavaScript內(nèi)存模型的深入理解對于編寫高效、穩(wěn)定的JavaScript應(yīng)用程序至關(guān)重要。我們要始終注意內(nèi)存泄漏問題,盡量避免全局變量和閉包等因素影響內(nèi)存回收,有效地釋放內(nèi)存,防止出現(xiàn)內(nèi)存溢出等問題。