V8引擎底层存储规则&垃圾回收机制

本文详细解析了JavaScript中的内存管理机制,包括栈内存、堆内存、池、函数缓存区和函数加载区的作用及特点。探讨了内存泄漏的原因,如闭包导致的内存常驻,以及如何避免内存泄漏。同时,介绍了V8引擎的垃圾回收机制,如标记-清除算法,以及函数作用域的创建过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内存问题 

下图中分了几个块:

  • 栈内存(只能从栈顶插入和删除元素,先进后出),存放变量和undifiend(没有内存地址可以指向),它的值都是内存地址。
  • 堆内存 存放对象和null,var  a = null和var b = null; 指向的是同一个内存地址;
  • 池,存放常量,同一个值只占有一块内存,只有三种类型 string number boolean的值
  • 函数缓存区, 存放函数,
  • 函数加载区,函数执行的时候占有的内存。

分别举例分析:

  • a是一个对象,指向的是堆中内存地址
  • b(string),c(number),d(boolean)指向的是池中的内存地址。
  • 再看m和n,通过构造函数的方式创建数值,会在栈中分别开辟空间存放变量m,和n,而他们都存放的都是池中的内存地址指向123,引用的是同一个值。但是m和n却是不同的。
  • 创建函数fun 函数加载区就会存放函数fun,如果我们通过var fun = function(){}的方式创建,这是栈中就会增加一个变量fun,指向函数加载区中的匿名函数。
  • 当函数调用的时候,就会在函数缓存区开辟一块空间,普通函数在执行结束,就会被释放。
  • new P() 通过new 关键字去调用一个函数, typeof 结果会是object,会在堆内存中开辟一块空间。

堆内存的回收是我们可以控制的,比如说对象a。如果设置为a = null, 堆内存会被回收掉。

常见的内存泄漏问题

内存泄漏:长期的持有一块内存的引用,让它得不到释放。不一定会报错。是一个绑定了执行环境的函数。与普通函数的区别就是他携带了执行环境。

       function fun() {
            height = 400
        }
        fun()
        console.log(height) //400
        function fun1() {
            this.mini = '小米'
        }
        fun1()
        console.log(mini) // 小米

内存常驻

节点移除以后,定时器会常驻内存中会 chrome浏览器可以通过下面方法查看cpu占用

闭包引起的内存泄漏

function Boyfriend() {
    this.name = '王源'
}
Boyfriend.prototype.findBoyfriend = function() {
    var _name = this.name;
    return function() {
        return _name
    }
}
var bf = new Boyfriend()
console.log(bf.findBoyfriend()()) // 王源
console.log(process.memoryUsage())

上面js代码在node中运行

rss总内存 heapTotal 堆内存 heapUsed实际使用的内存 external 引擎底层语言占用的内存 

内部的_name变量不会被回收掉。会常驻内存。所以我们应该换成下面的方式去写闭包。

function Boyfriend() {
    this.name = '王源'
}
Boyfriend.prototype.findBoyfriend = function() {
    var _name = this.name;
    return function() {
        return _name
    }
    _name = null
}
var bf = new Boyfriend()
console.log(bf.findBoyfriend()()) // 王源

实际使用的内存变小了。

垃圾回收机制

老的IE浏览器使用的垃圾回收方法。

function fun2() {
    var o1 = {
        a: 444
    }
    var o2 = {
        a: 444
    }
    // o1.a = o2;
    // o2.a = o1;
}
fun2()

看代码,循环引用不会被回收掉。

    function fun1() {
        var obj = {};
        var obj1 = {};
        obj.a = obj1;
        obj1.a = obj
    }
    fun1();

标记-清除算法

 

v8为什么要限制内存呢?

v8最初为浏览器设计,不要可能出现需要很大内存的场景

v8进行一次1.5GB以上的垃圾回收的时间在50ms到1s之间,为了防止因为垃圾回收造成的js线程暂停时间过长。

v8是一种分代回收的策略,将内存分为新生代,老生代

to空间是需要被回收掉的。

新声带对象的晋升

 老生代的标记合并

 

函数作用域问题

AO是函数作用域

GO是全局作用域 

function fun(a, b, c) {
        /*
         step 1 创建AO对象
         AO = {}
         step 2 初始化AO对象
         AO = {
             this: undifined;
             arguments: undifined;
             a: undifined;
             b: undifined;
             c: undifined;
             inner: undifined;
         }
         step 3 赋值
         AO = {
             this: window;
             arguments: [length:2,0:1,1:2];
             a: 1;
             b: 2;
             c: undifined;
             inner: undifined;
             fun: function fun(){}
         }
         step 4 函数覆盖值
         AO = {
            this: window;
            arguments: [length:2,0:1,1:2];
            a: function a() {};
            b: 2;
            c: undifined;
            inner: undifined;
         }
        */
        console.log(this) // window
        console.log(arguments) // 
        console.log(a)
        console.log(b)
        console.log(c)
        console.log(fun)
        console.log(inner)
        var inner = 20
        function fun() {

        }
        function a() {

        }
    }
    var global = 20
    fun(1,2);

 函数调用的时候,会首先创建一个AO对象,创建过程分为上面3步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值