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)