我正在参与掘金创作者训练营第6期,点击了解活动详情
内存管理
不同于一些底层语言例如c语言,在javascript语言中,创建变量的过程时就自动进行了分配内存,并且在不使用它们时有一个自动释放的操作,释放的过程被称为垃圾回收。
内存生命周期
几乎所有编程语言的生命周期都分为以下几步
分配需要的内存
var a = 1; // 给数据变量分配内存
var b = "bbb"; // 给字符串分配内存
var c = {
d: 1,
e: null
}; // 给数组及其包含的值分配内存
function f (g) {
return f;
}; // 给函数分配内存
使用分配的内存
对分配的内存进行读写操作,这个操作可能是写入一个变量或者一个对象的属性值。
使用完成后不需要时释放该内存
分配给对象以及变量的内存在不使用后进行释放以便下一次使用,避免耗尽计算机内存造成崩溃。
垃圾回收的方法
引用计数法
介绍
垃圾回收算法主要依赖于引用的概念。在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。例如,一个 Javascript 对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用)。
简单来说,当一个对象没有被其他对象引用到它,此时这个对象处于一个0引用的状态,它就会被垃圾回收机制回收。
也就意味着,当一个变量被引用时,此时引用次数+1;当该变量的引用被清除时,引用次数-1;当引用次数变成0时,将会释放它的内存。
let a = 1; // 1的内存被a引用,引用次数+1
a = 2; // 1的内存被清除引用,引用次数-1
let b = a; // 2的内存先后被a和b引用,引用次数为2
循环引用问题
在前面我们已经知道了,当变量的引用次数变为0时,就会被释放内存,那么如果对象互相被引用就永远不会被回收,执行多次后将会造成很严重的内存泄漏。
function test() {
let obj1 = {};
let obj2 = {};
obj1.a = obj2 // obj1 引用 obj2
obj2.a = obj1 // obj2 引用 obj1
}
test()
解决方法:函数结束时把对象指向null
obj1 = null;
obj2 = null;
标记引用法
为了避免出现循环引用的问题,Netscape Navigator 4.0 开始采用标记清除法。
垃圾回收机制会在运行的时候,会从根开始,找到所有从根开始引用的对象,然后找引用的对象引用的对象....然后给存储在内存里的所有变量都加上标记,同时会去掉环境中已经被标记为引用的变量。去掉之后,再被标记的变量就是可以被删除的变量,最后垃圾回收清除标记的变量回收内存空间,就完成了垃圾回收。
总结
本文简单介绍了两种垃圾回收的方法,旨在帮助读者对javascript里GC垃圾回收机制有一定的了解。