本文已参与「新人创作礼」活动,一起开启掘金创作之路。
什么是内存管理?
不管是什么样的编程语言,在代码的执行都是需要给它分配内存的,不同的是,某些编程语言会自动帮助我们管理内存。
而不管采用什么方式来管理内存,内存管理都会有如下的生命周期:
- 分配你所申请需要分配的内存;
- 使用分配的内存(存放一些东西,比如对象等);
- 当不需要使用内存时,对其进行释放;
不同的编程语言对于步骤1和步骤3会有不同的实现:
- 手动管理内存:比如C,C++,包括早期的Object C,都是需要手动来管理内存的申请和释放的(malloc和free函数);
- 自动管理内存:比如Java,JavaScript,Python,Swift,Dart等,它们会自动帮助我们管理内存;
JS的内存管理
当我们使用JavaScript定义变量时它会为我们分配内存,但是,对于不同的数据类型,内存的分配方式是不同的:
- 对于基本数据类型,内存的分配会在执行时,直接在栈空间进行分配;
- 对于复杂数据类型(如:对象,函数),内存的分配会在堆内存中开辟一块空间,并将这块空间的指针(即内存地址)返回给变量进行引用;
JS的垃圾回收
因为内存空间是有限的,因此当内存不再需要的时候,我们需要对其进行释放,以便腾出更多的内存空间。
在手动管理内存的语言中,我们需要自己通过一些方式来释放不需要的内存,但这种管理方式其实非常的低效,影响我们编写逻辑代码的效率;并且这种方式,对于开发者的要求也很高,容易一不小心就产生内存泄漏。
所谓的内存泄漏就是程序的某个位置在不需要使用内存的时候,仍然占据这块内存,对内存造成浪费。
因此,大部分的现代编程语言都是有自己的垃圾回收机制的:
- 垃圾回收,Garbage Collection,简称GC;
- 对于那些不再使用到的对象,我们都称之为垃圾,它需要被回收,以释放更多的内存空间;
- 而我们的语言运行环境,比如Java的运行环境JVM,JavaScript的运行环境JS引擎都内置了垃圾回收器;
垃圾回收器需要知道哪些对象是不再使用的,于是就需要用到GC算法
常见的GC算法
引用计数
- 当一个对象存在另一个对象对它进行引用时,那么这个对象的引用计数就+1,当引用计数为0的时候,就认为这个对象可以被销毁掉;
- 这个算法存在一个很大的弊端:无法处理循环引用的对象;
var person1 = {}
var person2 = {}
person1.friend = person2
person2.friend = person1
// 在上面的代码中,person1和person2都至少会存在一次引用
标记清除
- 这个算法会设置一个根对象(root object),垃圾回收器会定时地从这个根对象开始,找到所有从根对象开始有引用到的对象,对于哪些没有引用到的对象,就认为是不可用的对象;
- 能够很好地解决循环引用的问题;
- JS引擎比较广泛的采用的就是标记清除算法,当然类似于V8引擎为了进行更好的优化,它在算法的实现细节上也会结合 一些其他的算法 ;