JS查漏补缺——内存管理和垃圾回收

73 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

认识内存管理

不管什么样的编程语言,在代码的执行过程中都是需要给它分配内存的,不同的是某些编程语言需要我们自己手动的管理内存( 如:比如C、C++都是需要手动来管理内存的申请和释放的(malloc和free函数) 某些编程语言会可以自动帮助我们管理内存(如:JavaScript通常情况下不需要手动管理

内存管理的生命周期

  • 申请内存
  • 使用内存
  • 释放内存

JS的内存分配

JavaScript会在定义变量时为我们分配内存
而对于变量,它有两种类型:简单数据类型(内存直接存的值),分别是Undefined,Null,Boolean,Number,String,Symbol,还有一种复杂数据类型(内存存的是引用地址):Object(对象、数组、函数)。
这两种类型在内存管理中分配内存的方式是不一样的:

  • 简单数据类型(基本类型)的值直接在栈空间进行分配,值与值之间是独立存在,修改一个变量的值不会影响其他变量的值
  • 复杂数据类型(引用类型)存在堆内存中,每创建一个对象,就会在堆内存中开辟出一个新的空间,而变量保存的对象的内存地址(对象的引用,如果两个变量保存的同一个对象,当一个变量改变属性值时,另一个变量的属性值也会变 )

简单数据类型的内存分配

// 定义变量
var a = 1;
var b = 2;

Snipaste_2022-08-18_09-46-36.png

复杂数据类型的内存分配

// 定义变量
const a = 1;
const b = 2;
const info {
  name: 'eureka',
  age: 100
}
function foo() {
  var c = 3;
  var d = 4;
  console.log(a+b);
}

Snipaste_2022-08-18_10-04-04.png

JS的内存释放

因为内存的大小是有限的,所以当内存不再需要的时候,我们需要对其进行释放,以便腾出更多的内存空间。

因为JS不用手动去释放内存,它有自己的垃圾回收机制(Garbage Collection,简称:GC),那JavaScript是怎么判断这个内存不再使用,进而被当成垃圾回收呢?

  • 当对象不再被引用时,JavaScript就认为它不再使用 (通过引用计数来确认)
  • 对象不能从根上访问到时,JavaScript也会把它认定为是垃圾 (通过标记清除来确认)

常见的GC算法——引用计数

当一个对象有一个引用指向它时,那么这个对象的引用就+1,当一个对象的引用为0时,这个对象就可以被销毁掉;

使用引用计数会有一个很严重的问题:循环引用。 循环引用指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用,并且不能通过代码访问它们,这样它们的引用永远不会为0,垃圾回收机制不能将这两个对象释放,进而会造成内存泄露

let a = {
  name: 'a',
  dad: b
};
​
let b = {
 name: 'b',
 son: a
}
a = null;
b = null;

Snipaste_2022-08-18_11-45-41.png

常见的GC算法——标记清除

  • 这个算法是假定一个根对象(root object),垃圾回收器会定期从这个根开始,找所有从根开始有引用到的对象,对于哪些没有引用到的对象,就认为是不可用的对象;
  • 根对象在浏览器中是 window 对象,在 NodeJS 中是 global 对象,只有当程序退出或者关闭网页或者关闭浏览器的时候才会销毁。
  • 这个算法可以很好的解决循环引用的问题;

Snipaste_2022-08-18_12-38-19.png

参考文章

www.cnblogs.com/MomentYY/p/…