简介
一、像C语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()。相反,JavaScript是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。 释放的过程称为垃圾回收。这个“自动”是混乱的根源,并让JavaScript(和其他高级语言)开发者错误的感觉他们可以不关心内存管理。
内存生命周期
一、不管什么程序语言,内存生命周期基本是一致的:
- 分配你所需要的内存
- 使用分配到的内存(读、写)
- 不需要时将其释放\归还
所有语言第二部分都是明确的。第一和第三部分在底层语言中是明确的,但在像JavaScript这些高级语言中,大部分都是隐含的。
| 【示例】求值```javascript var a = {n: 1}; var b = a; a.x = a = {n: 2};
console.log(a); // => { n: 2 } console.log(b); // => { n: 1, x: { n: 2 }} console.log(a.x); // => undefined console.log(b.x); // => {n: 2}
1、优先级。.的优先级高于=,所以先执行a.x,堆内存中的{n: 1}就会变成{n: 1, x: undefined},改变之后相应的b.x也变化了,因为指向的是同一个对象。<br />2、赋值操作是从右到左,所以先执行a = {n: 2},a的引用就被改变了,然后这个返回值又赋值给了a.x,需要注意的是这时候a.x是第一步中的{n: 1, x: undefined}那个对象,其实就是b.x,相当于b.x = {n: 2}<br /> |
| --- |
<a name="xdJKo"></a>
### JavaScript 的内存分配
<a name="pHNMF"></a>
#### 值的初始化
一、为了不让程序员费心分配内存,JavaScript 在定义变量时就完成了内存分配。
| 【示例】```javascript
var n = 123; // 给数值变量分配内存
var s = "azerty"; // 给字符串分配内存
var o = {
a: 1,
b: null
}; // 给对象及其包含的值分配内存
// 给数组及其包含的值分配内存(就像对象一样)
var a = [1, null, "abra"];
function f(a){
return a + 2;
} // 给函数(可调用的对象)分配内存
// 函数表达式也能分配一个对象
someElement.addEventListener('click', function(){
someElement.style.backgroundColor = 'blue';
}, false);
| | —- |
通过函数调用分配内存
一、有些函数调用结果是分配对象内存:
| 【示例】```javascript var d = new Date(); // 分配一个 Date 对象
var e = document.createElement(‘div’); // 分配一个 DOM 元素
|
| --- |
二、有些方法分配新变量或者新对象:
| 【示例】```javascript
var s = "azerty";
var s2 = s.substr(0, 3); // s2 是一个新的字符串
// 因为字符串是不变量,
// JavaScript 可能决定不分配内存,
// 只是存储了 [0-3] 的范围。
var a = ["ouais ouais", "nan nan"];
var a2 = ["generation", "nan nan"];
var a3 = a.concat(a2);
// 新数组有四个元素,是 a 连接 a2 的结果
| | —- |
使用值
一、使用值的过程实际上是对分配内存进行读取与写入的操作。读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。
当内存不再需要使用时释放
一、大多数内存管理的问题都在这个阶段。在这里最艰难的任务是找到“哪些被分配的内存确实已经不再需要了”。它往往要求开发人员来确定在程序中哪一块内存不再需要并且释放它。
二、高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。
- 这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决)。
- 因为“不再需要”是无法判定的,所以垃圾回收只能有限制地解决一般问题。