1.内存泄露
有以下代码执行:
...
<script>
for(let i = 0; i < i+1; i++){
console.log(i)
}
</script>
...
会发生什么现象呢?
1.此时打开浏览器执行此html代码,会发生浏览器卡死现象,只能强制关闭浏览器
2.打开任务管理器,发现cpu占用100%,尤其是运行此代码的浏览器,几乎占满了cpu
明显看出,内存泄漏涉及到了硬件
2.堆栈溢出
有以下代码执行:
...
<script>
function test(){
test()
}
test()
console.log(123)
</script>
...
会发生什么现象呢?
1.此时打开浏览器执行此html代码,会看到浏览器报错:
2.后面的代码没有继续执行
3.浏览器正常使用,没有卡顿,且打开任务管理器可看到浏览器占用cpu没有发生明显变化
明显看出,堆栈溢出没有涉及到硬件,仅是浏览器执行上下文环境的一个异常
3.总结:
堆栈溢出仅是js语法环境的“栈”溢出,而内存泄漏是会涉及到电脑硬件(变量过多未回收或其他原因导致浏览器占用cpu过高,浏览器卡死)
4.附栈溢出示意图:
如图,一个递归没有终止条件,打个断点
点开浏览器跑一下,可以看到栈中存在一个test函数
点击下一步,栈中push了一个test函数
再点击下一步,栈中又push了一个test函数
...直到push超过了js栈的最大储存量,报错:栈溢出
5.扩展:堆栈溢出的处理
- 1.异步调用(必须是宏任务)
比如上面的递归改写一下
function test(){
setTimeout(() => {
test()
})
}
test()
这样就不会报错了,原理是什么呢?
js执行的规则是同步任务放到执行栈里,异步任务会先放到任务队列里,等同步任务执行后,再把异步任务push到执行栈里,依次执行
同步任务的执行顺序是先进后出
异步任务的执行顺序是先进先出
微任务先执行,全部拉入执行栈
宏任务后执行,一次拉入一个进入执行栈
正因为异步任务先进先出的特性和宏任务一次只会拉入一个进入执行栈的特性,所以宏任务能用来处理栈溢出
- 2.尾递归,复杂度由O(n)变为O(1)