无论是高级语言,仍是低级语言。内存的管理都是:node
前两步,你们都没有太大异议。关键是释放内存这一步,各类语言都有本身的垃圾回收(garbage collection, 简称GC)机制。作GC的第一步是判断堆中存的是数据仍是指针,是指针的话,说明它被指向活跃的对象。有3种判断方法:算法
对于JavaScript而言,最初的垃圾回收机制,是基于引用计次来作的。后来升级为标记清除。浏览器
当对象被引用次数为0时,就被回收。潜在的一个问题是:循环引用时,两个对象都至少被引用了一次,将不能自动被回收。因此致使,咱们常讲的内存泄露。函数
// 引用计次 var a = {t: 1}; // 对象 `{t: 1}` (如下简称obj)被引用一次 var b = a; // obj 被引用两次 a = null; // obj 如今为1次 b = null; // obj 如今为0次,可回收 // 循环引用 function fn() { var a = {}; var b = {}; a.b = b; b.a = a; } fn();
这是当前主流的GC算法,V8里面就是用这种。当对象,没法从根对象沿着引用遍历到,即不可达(unreachable),进行清除。对于上面的例子,fn()
里面的 a
和 b
在函数执行完毕后,就不能经过外面的上下文进行访问了,因此就能够清除了。post
下面,咱们简述下V8的GC机制:spa
在大部分的应用场景:一个新建立的对象,生命周期一般很短。因此,V8里面,GC处理分为两大类:新生代和老生代。指针
新生代的堆空间为1M~8M,并且被平分红两份(to-space和from-space),一般一个新建立的对象,内存被分配在新生代。当to-space满的时候,to-space和form-space交换位置(此时,to空,from满),并执行GC.若是一个对象被判定为,未被引用,就清除;有被引用,逃逸次数+1(若是此时逃逸次数为2,就移入老生代,不然移入to-space)。code
老生代的堆空间大,GC不适合像新生代那样,用平分红两个space这种空间换时间的方式。老生代的垃圾回收,分两个阶段:标记、清理(有Sweeping和Compacting这两种方式)。orm
标记,采用3色标记:黑、白、灰。步骤以下:对象
GC的时候,从根对象开始遍历。在浏览器,根对象是 window
;在 Node.js 中,是 global
(或称为root
).
Node.js中,每一个文件被当作一个模块,因此,当你用 var/let/const
在文件的全局,声明变量的时候,做用域是当前文件(模块)。所以,图中 root.a
是 undefined
.