study icon indicating copy to clipboard operation
study copied to clipboard

内存泄漏与垃圾回收机制

Open cfour-hi opened this issue 6 years ago • 0 comments


内存生命周期

不管什么程序语言,内存生命周期基本是一致的:

  1. 分配你所需要的内存
  2. 使用分配到的内存(读、写)
  3. 不需要时将其释放 \ 归还

在所有语言中第一和第二部分都很清晰,最后一步在底层语言中很清晰,但是在像 JavaScript 等上层语言中,这一步是隐藏的、透明的。

什么是内存泄漏?

内存不再被需要(使用)但没有被释放(回收)

在 JavaScript 这门高级语言中,内存管理依赖于 JS 引擎的垃圾回收机制。

什么是垃圾回收机制?

跟踪内存的分配和使用,当分配的内存不再使用时,自动释放它。

这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决)。

垃圾回收算法

  1. 引用计数 - 对象是否被引用

    最简单的垃圾收集算法,收集并记录对象被引用的次数,当对象引用次数为 0 时被回收。

    此算法的缺陷是无法处理循环引用:

    *** title ***
    function foo () {
      var oa = {}
      var ob = {}
      oa.b = ob // oa 引用 ob
      ob.a = oa // ob 引用 oa
    
      return 'azerty'
    }
    
    foo()
    

    上例中,两个对象被创建,并互相引用,形成了一个循环。它们被调用之后不会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。

  2. 引用标记 - 对象是否可获取

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

    此算法解决了循环引用的问题,上例中 foo 函数执行完毕后,全局对象将无法获取 foo 函数内定义的两个对象。

    此算法也有它的限制:那些无法从根对象查询到的对象都将被清除,不过无需担心,实践中我们很少会碰到类似的情况。

    从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。所有对 JavaScript 垃圾回收算法的改进都是基于标记 - 清除算法的改进,并没有改进标记 - 清除算法本身和它对“对象是否不再需要”的简化定义。

常见的内存泄漏和避免方式

4类 JavaScript 内存泄漏及如何避免

内存泄漏识别方式

JavaScript 内存泄漏教程

文中使用 chrome 开发者工具 timeline 面板查看内存占用方式需更改为 Performance 面板,并勾选 Memory 选项。

cfour-hi avatar Mar 17 '18 13:03 cfour-hi