Blog icon indicating copy to clipboard operation
Blog copied to clipboard

作用域与闭包 - 堆栈溢出和内存泄漏的原理及防范

Open logan70 opened this issue 5 years ago • 0 comments

堆栈溢出和内存泄漏的原理及防范

堆栈溢出

产生原因

  • 上溢:栈满时再做进栈必定产生空间溢出
  • 下溢:栈空时再做退栈也产生空间溢出

最常见的就是无限递归递归层级过深,导致调用栈空间不足,从而导致栈上溢。

// 阶乘,若用递归实现,层级不能过深
const factorial = n => n <=1 ? 1 : n * factorial(n - 1)
// 斐波那契数列也一样
const fibonacci = n => n <= 1 ? 1 : fibonacci(n - 1) + fibonacci(n - 2)

解决方案

递归改循环

优化原理:所有运算均在一个执行上下文中执行,不用生成额外的上下文。

const factorial = n => {
  let result = 1
  while (n > 1) {
    result *= n--
  }
  return result
}

const fibonacci = n => {
  let tmp = 1
  let result = 1
  while (n > 1) {
    [tmp, result] = [result, tmp + result]
    n--
  }
  return result
}

尾调用优化

优化原理:函数返回回溯时不需要做任何额外的计算,故可以不用保存函数的入口环境。

尾调用的优化依赖于语言实现,其本质还是将尾调用优化为循环的实现方式。ES6之前没有对尾调用进行优化,还是会导致调用栈增长。

const factorial = (n, result = 1) => n <= 1 ? result : factorial(n - 1, n * result)

const fibonacci = (n, prev = 1, cur = 1) => n <= 1 ? cur : fibonacci(n - 1, cur, prev + cur)`

内存泄漏

内存泄漏主要

产生原因

由于疏忽或错误造成程序未能释放已经不再使用的内存。

例如不再需要的闭包、定时器及全局变量等未能及时解除引用。

解决方案

  • 及时解除不再需要的引用,如闭包、定时器及全局变量等;
  • 使用WeakSetWeakMap,它们对于值的引用是弱引用,只要外部的引用消失,内部的引用就会自动被垃圾回收清除。

logan70 avatar Nov 29 '19 10:11 logan70