中高级前端必须了解的JS中的内存管理
前言 像C语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()用于分配内存和释放内存。 而对于JavaScript来说,会在创建变量(对象,字符串等)时分配内存,并且在不再使用它们时“自动”释放内存,这个自动释放内存的过程称为垃圾回收。 因为自动垃圾回收机制的存在,让大多Javascript开发者感觉他们可以不关心内存管理,所以会在一些情况下导致内存泄漏。 内存生命周期 JS 环境中分配的内存有如下声明周期:
JS 的内存分配 为了不让程序员费心分配内存,JavaScript 在定义变量时就完成了内存分配。
有些函数调用结果是分配对象内存:
有些方法分配新变量或者新对象:
JS 的内存使用 使用值的过程实际上是对分配内存进行读取与写入的操作。 读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。
JS 的内存回收 JS 有自动垃圾回收机制,那么这个自动垃圾回收机制的原理是什么呢? 其实很简单,就是找出那些不再继续使用的值,然后释放其占用的内存。 大多数内存管理的问题都在这个阶段。 在这里最艰难的任务是找到不再需要使用的变量。 不再需要使用的变量也就是生命周期结束的变量,是局部变量,局部变量只在函数的执行过程中存在, 当函数运行结束,没有其他引用(闭包),那么该变量会被标记回收。 全局变量的生命周期直至浏览器卸载页面才会结束,也就是说全局变量不会被当成垃圾回收。 因为自动垃圾回收机制的存在,开发人员可以不关心也不注意内存释放的有关问题,但对无用内存的释放这件事是客观存在的。 不幸的是,即使不考虑垃圾回收对性能的影响,目前最新的垃圾回收算法,也无法智能回收所有的极端情况。 接下来我们来探究一下 JS 垃圾回收的机制。 垃圾回收 引用 垃圾回收算法主要依赖于引用的概念。 在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。 例如,一个Javascript对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用)。 在这里,“对象”的概念不仅特指 JavaScript 对象,还包括函数作用域(或者全局词法作用域)。 引用计数垃圾收集 这是最初级的垃圾回收算法。 引用计数算法定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。 如果没有其他对象指向它了,说明该对象已经不再需了。
由上面可以看出,引用计数算法是个简单有效的算法。但它却存在一个致命的问题:循环引用。 如果两个对象相互引用,尽管他们已不再使用,垃圾回收不会进行回收,导致内存泄露。 (编辑:ASP站长网) |