温顾而知新:js中内存和垃圾回收机制

113 阅读3分钟

前言

不管什么程序的语言,内存生命周期基本都是一致的:

  1. 系统分配所需要的内存空间
  2. 程序使用内存(进行读写)
  3. 使用完成后释放内存空间(手动或自动)

在chrome浏览器中,V8被限制了内存的使用,64位约为1.4G,32位约为0.7G, 限制的主要原因是V8最初为浏览器设计,不太可能遇到大量使用内存的场景。更深层的原因是v8垃圾回收机制的限制,清理大量的内存垃圾很消耗时间,这样会引起JavaScript线程暂停执行,导致应用性能下降。

JavaScript在创建变量或对象时自动进行了内存分配,并且在程序不再使用它们时会自动释放,这个释放的过程称之为垃圾自动回收机制。

内存泄漏

在应用程序运行过程中,过去使用过但后续不再需要的变量或对象,由于没被释放掉,可能会引起程序的卡顿和崩溃,这些无用并且占用内存空间的变量,称之为内存泄漏

内存溢出

对于每个应用程序,系统会分配一定的内存空间,如果在程序运行过程中占用的内存不断的变大,超过系统所分配的空间,那么应该程序就会卡死,称之为内存溢出

JavaScript场景的四种内存泄漏

  • 声明过多的全局变量

  • 使用不当的闭包

  • 被遗忘的定时器以及监听回调函数

  • 未清理的DOM引用

垃圾回收机制

引用计数

这是最初的垃圾收集算法,此算法把对象是否不再需要简化定义为对象有没有其他对象引用到,如果没有引用指向该对象(零引用),那么垃圾回收机制会回收该对象,如果两个对象之间存在互相引用,可能会出现不会回收的现象。

标记清除

标记清除算法将不再使用的对象定义为无法达到的对象。简单来说,就是从根部(在js中就是全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,都是还需要使用的。那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收,大致的流程是:

  1. 垃圾收集器会在运行的时候给存储在内存中的所有变量都加上标记
  2. 从根部出发将能触及到的对象的标记进行清除
  3. 那些还存在标记的变量被视为准备删除的变量
  4. 最后垃圾收集器会执行最后一步内存的清除工作,销毁那些带标记的变量并回收它们所占用的内存空间

对于循环引用不再是问题了,两个循环引用的对象在垃圾收集时从全局对象出发无法再获取他们的引用,因此它们将被垃圾回收器回收

内存存储方案

javascript变量可以保存为两种数据类型的值:基本类型和引用类型

基本类型:String,Number,Boolean,Null,Undefined,BigInt,Symbol

引用类型:Object,Array,Function,Date等..

基本数据类型存储值的大小是固定的,存储在栈内存

引用数据类型引用值是对象,大小是不固定的,存储在堆内存上