三分钟快速理解javascript内存管理

2,474 阅读3分钟

javascript中具有垃圾自动回收机制(Garbage Collection),也就是执行环境会负责管理代码执行过程中使用的内存,在开发过程中就可以不考虑内存的分配,以及无用内存释放的问题.但是触发立即回收机制会中断代码的执行,停止其他操作,遍历所有的对象,回收所有不可访问的对象,因此垃圾回收的工作机制是周期性的.

因本文为快速理解内存管理所以相关涉及的知识:作用域链,闭包等概念我在这里就不做展开,想要去了解的朋友可以直接在掘金上浏览相关文章,有很多大牛的优秀文章值得一读

变量的生命周期

大家都知道javascript有作用域的概念,在局部作用域内用var关键字声明变量,函数执行结束,如果垃圾回收机制判断到此局部变量可以被回收,那么这个局部变量就会在内存中消失.

    function fn1(){
        var obj = {name: 'richard'}
    }
    function fn2(){
        var obj = {name: 'jungkkki'}
        return obj
    }
    var a = fn1() // undefined
    var b = fn1() // {name: 'jungkkki'}

fn1在函数内声明了局部变量obj并且赋值,在函数执行结束后,这个局部变量便再也无法访问到了,当垃圾回收机制周期性运行时,这个局部变量obj将被回收.

fn2在函数内声明了局部变量obj并且赋值,在函数执行结束后,这个局部变量返回值赋值给全局变量b,当垃圾回收机制周期性运行时,{name:'jungkkki'}的内存不会被回收.

分享知识点:解释型语言(例如 JavaScript)来说, 通过词法分析 -> 语法分析 -> 语法树,就可以开始解释执行了。
语法分析成 AST (Abstract Syntax Tree),大家可以在这里试试 http://esprima.org/

标记清除&引用计数

javascript如何来判断变量是否可以被访问那么就要提到辣鸡回收机制中标记清除和引用计数

   function test(){
       var one = {num: '1'} // 标记进入环境
       var two = {num: '2'} // 标记进入环境
   }
   test() // 函数执行完毕 one,two 标记离开环境

标记清除:通常javascript通过标记变量的状态来判断是否被回收,当变量在函数中被声明时标记进入环境,在函数执行结束时,环境被销毁标记离开环境等待回收.只要不释放进入环境的变量,他在环境中的任何位置任何时刻都可以被访问,就不会被垃圾回收机所回收.

   function test2(){
       var a = {name: 'richard'} // {name: 'richard'} 引用次数1
       a = {name: 'jungkkki'} // {name: 'richard'} 引用次数 -1 直接标记,等待回收 {name; 'jungkkki'} 引用次数+1
   }
   test() // 函数执行结束 环境销毁 {name: 'jungkkku'}等待回收

引用计数:javascript去维护一张表,存储内存中资源的引用次数,资源被引用+1,结束引用或者函数执行完毕结束作用域,引用次数-1,引用次数由1到0时不会执行,节省开销,直接标记

GC 的缺陷、分代回收和增量 GC

和其他语言一样 GC 会中断代码执行,停止其他操作。因为要遍历所有对象,回收所有不可访问对象,这个操作的耗时可能有 100ms 以上。在 V8 引擎新版本中引入了两种优化方法:1. 分代回收(Generation GC),2. 增量 GC(increment GC)

分代回收:目的是通过对象的使用频率、存在时长区分新生代与老生代对象。多回收新生代区(young generation),少回收老生代区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时

增量 GC:把需要长耗时的遍历、回收操作拆分运行,减少中断时间,但是会增大上下文切换开销.

喜欢的朋友可以随手点赞和关注,有大家的支持就有了更多的动力

![](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/10/23/c7095c96db3d54b6d71c17e48fcc3cb0~tplv-t2oaga2asx-image.image)