JS中内存管理知多少

62 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

什么是内存管理?

不管是什么样的编程语言,在代码的执行都是需要给它分配内存的,不同的是,某些编程语言会自动帮助我们管理内存。

而不管采用什么方式来管理内存,内存管理都会有如下的生命周期:

  1. 分配你所申请需要分配的内存;
  2. 使用分配的内存(存放一些东西,比如对象等);
  3. 当不需要使用内存时,对其进行释放;

不同的编程语言对于步骤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引擎为了进行更好的优化,它在算法的实现细节上也会结合 一些其他的算法 ;