logan70 / Blog

写博客的地方,觉得有用的给个Star支持一下~
81 stars 9 forks source link

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

Open logan70 opened 4 years ago

logan70 commented 4 years ago

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

堆栈溢出

产生原因

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

// 阶乘,若用递归实现,层级不能过深
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)`

内存泄漏

内存泄漏主要

产生原因

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

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

解决方案