1

内存模型

  • 堆(引入数据类型:Object,Array)
  • 栈(基本数据类型:Undefined、Null、Boolean、Number和String)
  • 池(常量:const)
内存分配问题举例
let a = 10;
let b = a;
b = 20;
console.log(a)  // 10

image

let obj = {
    aa: 20,
    bb: 30
}
let newObj = obj;
newObj.aa = 10;
console.log(obj.aa)  // 10

image

内存的生命周期

let obj = {
    aa: 20,
    bb: 30
}
console.log(obj)  // 后面没有再使用,js机制会自动回收,这就是内存的生命周期

内存泄漏

// 导致内存泄漏的例子1
function fn(){
    demo = '我很棒'  // window.demo = '我很棒'
}
fn();
console.log(this.demo)  // 我很棒
// 导致内存泄漏的例子2
function fn2(){
    this.demo2 = 123;
}
fn2();
console.log(this.demo2)  // 123
// 闭包导致的内存泄漏
function findBF() {
    this.name = '肖战';
    this.leg = 165;
}
findBF.prototype.selectName = function() {
    let _this = this; // 有问题 js内存机制  1、全局变量不会回收  2、闭包内的变量也会持续保存在闭包中
    return function() {
        return _this.name;;
    }
    name = null;
}
let bf = new findBF();
console.log(bf.selectName()());
可通过chrome的工具查看内存情况(缺点:不够清晰)

image

使用node查看内存情况(可查看到具体的内存使用情况)
console.log(process.memoryUsage());

image

优化
function findBF() {
    this.name = '肖战';
    this.leg = 165;
}
findBF.prototype.selectName = function() {
    let name = this.name;
    return function() {
        return name;
    }
    name = null;
}
let bf = new findBF();
console.log(bf.selectName()());
console.log(process.memoryUsage());

image

内存常驻

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div class="test">
        <p id="demo">好好学习</p>
        <button id="btn">移除节点</button>
    </div>
</body>
<script>
    window.onload = () => {
        let dom = document.getElementById('demo');
        setInterval(() => {
            let time = new Date();
            if (dom) {
                dom.innerHTML = JSON.stringify(time);
            }
            console.log('time');  // 即使节点移除,time也会一直打印,存在内存常驻问题
        }, 1000);

        let btn = document.getElementById('btn');
        btn.onclick = () => {
            dom.remove();
        }
    }
</script>

</html>
优化
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div class="test">
        <p id="demo">好好学习</p>
        <button id="btn">移除节点</button>
    </div>
</body>
<script>
    window.onload = () => {
        let dom = document.getElementById('demo');
        let timeInterval = setInterval(() => {
            let time = new Date();
            if (dom) {
                dom.innerHTML = JSON.stringify(time);
            }
            console.log('time');  // 即使节点移除,time也会一直打印,存在内存常驻问题
        }, 1000);

        let btn = document.getElementById('btn');
        btn.onclick = () => {
            // 显示的移除
            clearInterval(timeInterval);
            dom.remove();
        }
    }
</script>

</html>

垃圾回收机制

未创建对象前的内存

image

// 垃圾回收 引用 所以不会被回收
let o = {
    a: {
        b: 2
    }
}

创建对象后的内存

image

let o = {
    a: {
        b: 2
    }
}

let o2 = 0;  // o2对o进行了引用 o的原始引用被o2替换掉了
// o 是一个零引用状态
o = 1;

let oa = o2.a;
o2 = 'test';

o不会被回收,因为o的属性a还在被调用

image

let o = {
    a: {
        b: 2
    }
}

let o2 = 0;  // o2对o进行了引用 o的原始引用被o2替换掉了
// o 是一个零引用状态
o = 1;

let oa = o2.a;
o2 = 'test';
oa = null;  // 释放内存

image

引用

垃圾回收算法主要依赖引用的概念。在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显示),叫做一个对象引用另一个对象。例如,一个JavaScript对象具有对它原型的引用(隐式引用)和对它属性的引用(显示引用)。

”对象“的概念不仅特指JavaScript对象,还包括函数作用域(或者全局词法作用域)。

引用计数垃圾收集

初级的垃圾收集算法。此算法把”对象是否不再需要“简化定义为”对象有没有其他对象引用到它“。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。

缺点:循环引用不会被回收

function fn2(){
    let o = {};
    let o2 = {};
    o.a = o2;
    o2.a = o;
}
fn2();

标记清除算法

设置一个叫做根(root)的对象(在JavaScript里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象......从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。

缺点:无法从根对象查询到的对象都将被清除(可被忽略)


洁本佳人
86 声望3 粉丝

test