天天看点

JavaScript内存管理以及GC算法内存管理什么是垃圾GC回收算法

内存管理以及GC算法

  • 内存管理
    • JavaScript的内存管理
  • 什么是垃圾
  • GC回收算法
    • 引用计数算法
    • 标记清除算法
    • 标记整理算法

内存管理

内存管理是开发者申请,使用,释放内存的过程,但JavaScript的内存管理是自动的,它内部并没有暴露api给开发者去操作内存。

JavaScript的内存管理

JavaScript并没有直接暴露api给开发者去申请,使用以及释放内存,它内部会自动分配内存

申请内存

// javascript 在声明变量的时候会自动分配一定的内存空间
let a = []
           

使用内存

// 使用内存实际就是对变量进行读写操作
let a = {}
// 写操作
a.name = 'xiaoming'
// 读操作
console.log(a.name)
           

释放内存

// JavaScript 中会自动回收垃圾变量,当对象不再被引用或者不是可达对象就被视为垃圾
let a = {}
a = null
// 此时 {} 没有被引用,就会被JavaScript内部的机制自动回收
           

什么是垃圾

上面说到JavaScript会自动回收垃圾变量,那么什么是垃圾呢?

对象不再被引用

我们都知道,

let a = {}

实际是a变量指向

{}

的地址,当

a

赋值为空的时候,

a

不在指向

{}

,此时没有变量指向

{}

的内存空间地址,

{}

就是垃圾

// a引用{}
let a = {}
// b = a,因此b和a都指向{},所以b也引用了{}
let b = a
// a不再引用{},但b还再引用{},所以{}不是垃圾
a = null
// b也不再引用{},{}是垃圾
b = null
           

对象不能从根上访问

这里的根指的是全局,对象如果能在全局通过引用或者作用域链被访问到,则视为可达对象,否则视为垃圾

function test() {
	let a = {}
}
test()
// 函数test执行完毕后,a变量无法在全局被访问到,因此a是垃圾,被回收
function get() {
	let b = {}
	return b
}
let _b = get()
// 函数get执行完毕后,b变量被全局下的_b接收,在全局我们可以通过_b访问到b变量,因此b不是垃圾,不会被回收
           

GC回收算法

引用计数算法

引用计数算法,会记录对象被引用的次数,当引用次数为0的时候,就会立即被回收

let a = {} // 计数1
let b = {}
b.obj = a // 计数2
a = null // 计数1
b.obj = null // 计数0 回收
           

优缺点

  • 可以即时回收垃圾对象
  • 减少程序卡顿时间
  • 无法回收循环引用对象
  • 消耗资源较大

疑问

  • 对于循环引用对象无法被回收的概念还是不太了解
  • 还有函数内部的对象被引用会不会计数

标记清除算法

标记清除算法的原理是:

  • 循环全局下所有对象,并标记可达对象
  • 循环全局下所有对象,并释放没有被标记的对象
  • 将释放的空间放入空闲列表

当再次申请内存的时候可以直接在空闲列表申请,优化申请的速度,但由于在申请空间的时候,空间是不连续的,所以空闲列表的空间内存是碎片化的,在某些情况下不能被很好的利用

优缺点

  • 可以回收循环引用的对象
  • 容易产生碎片化空间,不利于再次利用,造成浪费
  • 不会立即回收垃圾对象

标记整理算法

标记清除算法的原理是:

  • 循环全局下所有对象,并标记可达对象
  • 循环全局下所有对象,并释放没有被标记的对象
  • 将释放的空间放入空闲列表,并整理空闲列表中的碎片化空间,使其最大程度的连续放置

标记整理实际是标记清除的优化版本,优化了碎片空间的难以利用性

优缺点

  • 可以回收循环引用的对象
  • 不会立即回收垃圾对象

继续阅读