- 内存分配:内存模型
- 生命周期:内存的生命周期、内存泄漏、内存常驻
- 垃圾回收:垃圾回收机制
内存模型
- 堆:引入数据类型: Object, Array
- 栈:基本数据类型:undefined、null、boolean、number、 string
- 池:常量:const
连续性内存,存在栈顶和栈底
堆栈: 进栈、出栈,先进后出、后进先出
引用类型, 新建对象存在内存,是个内存地址。
队列 先进先出
1
2
3
4
5
6
7
| let arr = new Array();
// 队列 先进先出
arr.unshift(1);
arr.unshift(2);
arr.unshift(3);
arr.pop();
console.log(arr); // [3, 2]
|
堆栈
1
2
3
4
5
6
| let arr2 = new Array();
arr2.push(1);
arr2.push(2);
arr2.push(3);
arr2.pop();
console.log(arr2); // [1, 2]
|
基本类型
1
2
3
4
| let a = 10;
let b = a;
b = 20;
console.log(a); // 10
|
引用类型
1
2
3
4
| let obj = {aa:20, bb:30};
let obk = obj;
obk.aa = 10;
console.log(obj.aa); // 10
|
内存的生命周期、内存泄漏、内存常驻
1 内存泄漏, 无声明
1
2
3
4
5
6
7
| // 内存泄漏
function fn(){
// 无声明就是全局变量, 相对于window.demo,导致内存泄漏
demo = "测试";
// let demo = "测试";
}
fn();
|
指向全局window,导致内存泄漏
1
2
3
4
5
| function fn2() {
// 指向全局window,导致内存泄漏
this.demo2 = 123;
}
fn2();
|
垃圾回收机制
垃圾回收算法主要依赖于引用的概念。
在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫一个对象引用另一个对象。“对象” 的概念不仅特指javascript对象,还包括函数作用域(或者全局词法作用域)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // 垃圾回收机制
let o = {
a: {
b: 2
}
}
// 以上o没有回收,引用操作
let o2 = o; // o2引用了o
// o是一个零引用状态
o = 1;
// 没有被回收,因为属性a还在被调用
let oa = o2.a;
console.log(o); // 1
o2 = 'wendy';
// 进行手动主动回收
oa = null; // 释放内存
|
1 引用计数垃圾收集
初级的垃圾收集算法,对象是否不再需要即对象有没有其他对象引用到它,如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。
缺点:循环引用不会被回收
1
2
3
4
5
6
7
8
9
10
11
| // 引用计数垃圾收集
function fn3(){
let o = {};
let o2 = {};
// 循环引用,没被释放
// 相互引用,不会被回收
o.a = o2;
o2.a = o;
}
fn3();
|
2 标记 - 清除算法
设置一个叫做根(root)的对象(在javascript里,根是全局变量)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象…从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象
缺点: 无法从根对象查询到的对象都将被清除(可被忽略)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| // <p id="domP"><p> <button id="btn">移除p节点<button>
window.onload = () => {
let domP = document.getElementById('domP');
const timeInerval = setInterval(()=>{
let time = new Date();
if(domP){
domP.innerHTML = JSON.stringify(time);
}
}, 1000);
let btn = document.getElementById('btn');
btn.onclick = () => {
// 显示的移除
clearInterval(timeInerval);
domP.remove();
}
// 闭包,作用域。全局访问不了局部,通过闭包return
// 闭包不能保持太多变量,会导致内存溢出。需要及时对闭包变量进行回收
function findGf(){
this.name = '名字';
this.let = 160;
}
findGf.prototype.selectName = function(){
// 这里会存在大量的变量
// let _this = this;
// 单独处理,并回收
let name = this.name;
return function(){
return name;
}
// 进行回收
name = null;
}
let gf = new findGf();
console.log(gf.selectName()());
// node
console.log(process.memoryUsage());
}
|
温馨提示:少定义全局变量,定时器要及时清除、对一些全局变量(常驻内存)及时释放。