欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文搞懂JavaScript中的內(nèi)存泄露

 更新時(shí)間:2022年06月18日 09:25:03   作者:諸葛小愚  
以前我們說(shuō)的內(nèi)存泄漏,通常發(fā)生在后端,但是不代表前端就不會(huì)有內(nèi)存泄漏。特別是當(dāng)前端項(xiàng)目變得越來(lái)越復(fù)雜后,前端也逐漸稱(chēng)為內(nèi)存泄漏的高發(fā)區(qū)。本文就帶大家了解一下Javascript的內(nèi)存泄漏

以前我們說(shuō)的內(nèi)存泄漏,通常發(fā)生在后端,但是不代表前端就不會(huì)有內(nèi)存泄漏。特別是當(dāng)前端項(xiàng)目變得越來(lái)越復(fù)雜后,前端也逐漸稱(chēng)為內(nèi)存泄漏的高發(fā)區(qū)。本文就帶你認(rèn)識(shí)一下Javascript的內(nèi)存泄漏。

什么是內(nèi)存泄漏

什么是內(nèi)存??jī)?nèi)存其實(shí)就是程序在運(yùn)行時(shí),系統(tǒng)為其分配的一塊存儲(chǔ)空間。每一塊內(nèi)存都有對(duì)應(yīng)的生命周期:

  • 內(nèi)存分配:在聲明變量、函數(shù)時(shí),系統(tǒng)分配的內(nèi)存空間
  • 內(nèi)存使用:對(duì)分配到的內(nèi)存進(jìn)行讀/寫(xiě)操作,即訪問(wèn)并使用變量、函數(shù)等
  • 釋放內(nèi)存:內(nèi)存使用完畢后,釋放掉不再被使用的內(nèi)存

不像C語(yǔ)言等底層語(yǔ)言需要程序員在開(kāi)發(fā)的時(shí)候自己通過(guò)mallocfree來(lái)申請(qǐng)或者釋放內(nèi)存,JavaScript同大多數(shù)現(xiàn)代編程語(yǔ)言一樣,都實(shí)現(xiàn)了給變量自動(dòng)分配內(nèi)存,并且在不使用變量的時(shí)候“自動(dòng)”釋放內(nèi)存,這個(gè)釋放內(nèi)存的過(guò)程就被稱(chēng)為垃圾回收。

每一個(gè)程序的運(yùn)行都需要一塊內(nèi)存空間,如果某一塊內(nèi)存空間在使用后未被釋放,并且持續(xù)累積,導(dǎo)致未釋放的內(nèi)存空間越積越多,直至用盡全部的內(nèi)存空間。程序?qū)o(wú)法正常運(yùn)行,直觀體現(xiàn)就是程序卡死,系統(tǒng)崩潰,這一現(xiàn)象就被稱(chēng)為內(nèi)存泄漏。

我們來(lái)舉幾個(gè)例子說(shuō)明一下:

內(nèi)存分配

const obj = {
    name: '張三'
} // 給{name: '張三'}分配內(nèi)存
function foo() {
    console.log('hello world')
} // 給函數(shù)分配內(nèi)存
let date = new Date(); // 根據(jù)函數(shù)返回的結(jié)果創(chuàng)建變量,會(huì)分配一個(gè)Date對(duì)象

可能發(fā)生內(nèi)存泄漏

function foo() {
    const obj = {name: '張三'}
    window.obj = obj;
    console.log(obj)
}
foo(); // foo()執(zhí)行完畢,{name: '張三'}對(duì)應(yīng)的內(nèi)存空間本應(yīng)該被釋放,但是由于又被全局變量所引用,因此其對(duì)應(yīng)的內(nèi)存空間不會(huì)被垃圾回收

閉包的內(nèi)存占用

function bar() {
    const data = {}
    return {
        get(key) {
            return data[key]
        },
        set(key, value) {
            data[key] = value
        }
    }; // 閉包對(duì)象
}
const {get, set} = bar; // 結(jié)構(gòu)
set('name', '張三')
get('name'); // 張三
// 函數(shù)執(zhí)行完畢,data對(duì)象并不會(huì)被垃圾回收,這是閉包的機(jī)制

內(nèi)存泄漏聽(tīng)起來(lái)可能會(huì)有點(diǎn)抽象,怎么能比較直觀的看到內(nèi)存泄漏的過(guò)程呢?

怎么檢測(cè)內(nèi)存泄漏

內(nèi)存泄漏主要是指的是內(nèi)存持續(xù)升高,但是如果是正常的內(nèi)存增長(zhǎng)的話,不應(yīng)該被當(dāng)作內(nèi)存泄漏來(lái)排查。排查內(nèi)存泄漏,我們可以借助Chrome DevTools的Performance和Memory選項(xiàng)。舉個(gè)栗子:

我們新建一個(gè)memory.html的文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {
      text-align: center;
    }
  </style>
</head>
<body>
  <p>檢測(cè)內(nèi)存變化</p>
  <button id="btn">開(kāi)始</button>
  <script>
    const arr = [];
    // 數(shù)組中添加100萬(wàn)個(gè)數(shù)據(jù)
    for (let i = 0; i < 100 * 10000; i++) {
      arr.push(i)
    }
    function bind() {
      const obj = {
        str: JSON.stringify(arr) // 淺拷貝的方式創(chuàng)建一個(gè)比較大的字符串
      }
      // 每次調(diào)用bind函數(shù),都在全局綁定一個(gè)onclick監(jiān)聽(tīng)事件,不一定非要執(zhí)行
      // 使用綁定事件,主要是為了保持obj被全局標(biāo)記
      window.addEventListener('click', () => {
        // 引用對(duì)象obj
        console.log(obj);
      })
    }
    let n = 0;
    function start() {
      setTimeout(() => {
        bind(); // 調(diào)用bind函數(shù)
        n++; // 循環(huán)次數(shù)增加
        if (n < 50) {
          start(); // 循環(huán)執(zhí)行50次,注意這里并沒(méi)有使用setInterval定時(shí)器
        } else {
          alert('done');
        }
      }, 200);
    }
    document.getElementById('btn').addEventListener('click', () => {
      start();
    })
  </script>
</body>
</html>

在無(wú)法確定是否發(fā)生內(nèi)存泄漏時(shí),我們可以先使用Performance來(lái)錄制一段頁(yè)面加載的性能變化,先判斷是否有內(nèi)存泄漏發(fā)生。

Performance

本次案例僅以Chrome瀏覽器展開(kāi)描述,其他瀏覽器可能會(huì)有些許差異。首先我們鼠標(biāo)右鍵選擇檢查或者直接F12進(jìn)入DevTools頁(yè)面,面板上選擇Performance,選擇后應(yīng)該是如下頁(yè)面:

在開(kāi)始之前,我們先點(diǎn)擊一下Collect garbageclear來(lái)保證內(nèi)存干凈,沒(méi)有其他遺留內(nèi)存的干擾。然后我們點(diǎn)擊Record來(lái)開(kāi)始錄制,并且同時(shí)我們也要點(diǎn)擊頁(yè)面上的開(kāi)始按鈕,讓我們的代碼跑起來(lái)。等到代碼結(jié)束后,我們?cè)冱c(diǎn)擊Record按鈕以停止錄制,錄制的時(shí)間跟代碼執(zhí)行的時(shí)間相比會(huì)有出入,只要保證代碼是完全執(zhí)行完畢的即可。停止錄制后,我們會(huì)得到如下的結(jié)果:

Performance的內(nèi)容很多,我們只需要關(guān)注內(nèi)存的變化,由此圖可見(jiàn),內(nèi)存這塊區(qū)域的曲線是在一直升高的并且到達(dá)頂點(diǎn)后并沒(méi)有回落,這就有可能發(fā)生了內(nèi)存泄漏。因?yàn)檎5膬?nèi)存變化曲線應(yīng)該是類(lèi)似于“鋸齒”,也就是有上有下,正常增長(zhǎng)后會(huì)有一定的回落,但不一定回落到和初始值一樣。而且我們還可以隱約看到程序運(yùn)行結(jié)束后,內(nèi)存從初始的6.2MB增加到了差不多351MB,這個(gè)數(shù)量級(jí)的增加還是挺明顯的。我們只是執(zhí)行了50次循環(huán),如果執(zhí)行的次數(shù)更多,將會(huì)耗盡瀏覽器的內(nèi)存空間,導(dǎo)致頁(yè)面卡死。

雖然是有內(nèi)存泄漏,但是如果我們想進(jìn)一步看內(nèi)存泄漏發(fā)生的地方,那么Performance就不夠用了,這個(gè)時(shí)候我們就需要使用Memory面板。

Memory

DevTools的Memory選項(xiàng)主要是用來(lái)錄制堆內(nèi)存的快照,為的是進(jìn)一步分析內(nèi)存泄漏的詳細(xì)信息。有人可能會(huì)說(shuō),為啥不一開(kāi)始就直接使用Memory呢,反而是先使用Performance。因?yàn)槲覀儎傞_(kāi)始就說(shuō)了,內(nèi)存增長(zhǎng)不表示就一定出現(xiàn)了內(nèi)存泄漏,有可能是正常的增長(zhǎng),直接使用Memory來(lái)分析可能得不到正確的結(jié)果。

我們先來(lái)看一下怎么使用Memory

首先選擇Memory選項(xiàng),然后清除緩存,在配置選項(xiàng)中選擇堆內(nèi)存快照。內(nèi)存快照每次點(diǎn)擊錄制按鈕都會(huì)記錄當(dāng)前的內(nèi)存使用情況,我們可以在程序開(kāi)始前點(diǎn)擊一下記錄初始的內(nèi)存使用,代碼結(jié)束后再點(diǎn)一下記錄最終的內(nèi)存使用,中間可以點(diǎn)擊也可以不點(diǎn)擊。最后在快照列表中至少可以得到兩個(gè)內(nèi)存記錄:

初始內(nèi)存我們暫時(shí)不深究,我們選擇列表的最后一條記錄,然后在篩選下拉框選擇最后一個(gè),即第一個(gè)快照和第二個(gè)快照的差異。

這里我們重點(diǎn)說(shuō)一下Shallow SizeRetained Size的區(qū)別:

  • Shallow Size:對(duì)象自身占用的內(nèi)存大小,一般來(lái)說(shuō)字符串、數(shù)組的Shallow Size都會(huì)比較大
  • Retained Size:這個(gè)是對(duì)象自身占用的內(nèi)存加上無(wú)法被GC釋放的內(nèi)存的大小,如果Retained Size和Shallow Size相差不大,基本上可以判定沒(méi)有發(fā)生內(nèi)存泄漏,但是如果相差很大,例如上圖的Object,這就表明發(fā)生了內(nèi)存泄漏。

我們?cè)賮?lái)細(xì)看一下Object,任意展開(kāi)一個(gè)對(duì)象,可以在樹(shù)結(jié)構(gòu)中發(fā)現(xiàn)每一個(gè)對(duì)象都有一個(gè)全局事件綁定,并且占用了較大的內(nèi)存空間。解決本案例涉及的內(nèi)存泄漏也比較簡(jiǎn)單,就是及時(shí)釋放綁定的全局事件。

關(guān)于PerformanceMemory的詳細(xì)使用可以參考:手把手教你排查Javascript內(nèi)存泄漏

內(nèi)存泄漏的場(chǎng)景

大多數(shù)情況下,垃圾回收器會(huì)幫我們及時(shí)釋放內(nèi)存,一般不會(huì)發(fā)生內(nèi)存泄漏。但是有些場(chǎng)景是內(nèi)存泄漏的高發(fā)區(qū),我們?cè)谑褂玫臅r(shí)候一定要注意:

我們?cè)陂_(kāi)發(fā)的時(shí)候經(jīng)常會(huì)使用console在控制臺(tái)打印信息,但這也會(huì)帶來(lái)一個(gè)問(wèn)題:被console使用的對(duì)象是不能被垃圾回收的,這就可能會(huì)導(dǎo)致內(nèi)存泄漏。因此在生產(chǎn)環(huán)境中不建議使用console.log()的理由就又可以加上一條了

被全局變量、全局函數(shù)引用的對(duì)象,在Vue組件銷(xiāo)毀時(shí)未清除,可能會(huì)導(dǎo)致內(nèi)存泄漏

// Vue3
<script setup>
import {onMounted, onBeforeUnmount, reactive} from 'vue'
const arr = reactive([1,2,3]);
onMounted(() => {
    window.arr = arr; // 被全局變量引用
    window.arrFunc = () => {
        console.log(arr); // 被全局函數(shù)引用
    }
})
// 正確的方式
onBeforeUnmount(() => {
    window.arr = null;
    window.arrFunc = null;
})
</script>

定時(shí)器未及時(shí)在Vue組件銷(xiāo)毀時(shí)清除,可能會(huì)導(dǎo)致內(nèi)存泄漏

// Vue3
<script setup>
import {onMounted, onBeforeUnmount, reactive} from 'vue'
const arr = reactive([1,2,3]);
const timer = reactive(null);
onMounted(() => {
    setInterval(() => {
        console.log(arr); // arr被定時(shí)器占用,無(wú)法被垃圾回收
    }, 200);
    // 正確的方式
    timer = setInterval(() => {
        console.log(arr);
    }, 200);
})
// 正確的方式
onBeforeUnmount(() => {
    if (timer) {
        clearInterval(timer);
        timer = null;
    }
})
</script>

setTimeoutsetInterval兩個(gè)定時(shí)器在使用時(shí)都應(yīng)該注意是否需要清理定時(shí)器,特別是setInterval,一定要注意清除。

綁定的事件未及時(shí)在Vue組件銷(xiāo)毀時(shí)清除,可能會(huì)導(dǎo)致內(nèi)存泄漏

綁定事件在實(shí)際開(kāi)發(fā)中經(jīng)常遇到,我們一般使用addEventListener來(lái)創(chuàng)建。

// Vue3
<script setup>
import {onMounted, onBeforeUnmount, reactive} from 'vue'
const arr = reactive([1,2,3]);
const printArr = () => {
    console.log(arr)
}
onMounted(() => {
    // 監(jiān)聽(tīng)事件綁定的函數(shù)為匿名函數(shù),將無(wú)法被清除
    window.addEventListener('click', () => {
        console.log(arr); // 全局綁定的click事件,arr被引用,將無(wú)法被垃圾回收
    })
    // 正確的方式
    window.addEventListener('click', printArr);
})
// 正確的方式
onBeforeUnmount(() => {
    // 注意清除綁定事件需要前后是同一個(gè)函數(shù),如果函數(shù)不同將不會(huì)清除
    window.removeEventListener('click', printArr);
})
</script>

被自定義事件引用,在Vue組件銷(xiāo)毀時(shí)未清除,可能會(huì)導(dǎo)致內(nèi)存泄漏

自定義事件通過(guò)emit/on來(lái)發(fā)起和監(jiān)聽(tīng),清除自定義事件和綁定事件差不多,不同的是需要調(diào)用off方法

// Vue3
<script setup>
import {onMounted, onBeforeUnmount, reactive} from 'vue'
import event from './event.js'; // 自定義事件
const arr = reactive([1,2,3]);
const printArr = () => {
    console.log(arr)
}
onMounted(() => {
    // 使用匿名函數(shù),會(huì)導(dǎo)致自定義事件無(wú)法被清除
    event.on('printArr', () => {
        console.log(arr)
    })
    // 正確的方式
    event.on('printArr', printArr)
})
// 正確的方式
onBeforeUnmount(() => {
    // 注意清除自定義事件需要前后是同一個(gè)函數(shù),如果函數(shù)不同將不會(huì)清除
    event.off('printArr', printArr)
})
</script>

除了及時(shí)清除監(jiān)聽(tīng)器、事件等,對(duì)于全局變量的引用,我們可以選擇WeakMap、WeakSet等弱引用數(shù)據(jù)類(lèi)型。這樣的話,即使我們引用的對(duì)象數(shù)據(jù)要被垃圾回收,弱引用的全局變量并不會(huì)阻止GC。

垃圾回收算法

我們知道了內(nèi)存泄漏的含義,也知道了怎么來(lái)檢測(cè)內(nèi)存泄漏,甚至可以一定程度上規(guī)避內(nèi)存泄漏了。除了那些容易產(chǎn)生內(nèi)存泄漏的場(chǎng)景,js是使用什么樣的機(jī)制來(lái)保證垃圾會(huì)被盡可能的回收呢?垃圾回收算法早期使用的是引用計(jì)數(shù),現(xiàn)在主流都采用標(biāo)記清除的方式了。

引用計(jì)數(shù)

我們創(chuàng)建一個(gè)對(duì)象,js會(huì)在堆內(nèi)存中分配一塊區(qū)域用于存儲(chǔ)對(duì)象信息,并且在棧中存在對(duì)象數(shù)據(jù)的引用地址。舉個(gè)栗子:

let obj = {name: '張三'};
let obj2 = obj;
// 對(duì)象數(shù)據(jù){name: '張三'}被obj和obj2引用,引用計(jì)數(shù)為2,此時(shí){name: '張三'}不能被垃圾回收
obj = 0; // obj雖然不引用{name: '張三'},但是obj2還在引用,此時(shí){name: '張三'}也不能被垃圾回收
obj2 = 0; // 此時(shí)的{name: '張三'}已經(jīng)是零引用了,可以被垃圾回收

下圖為創(chuàng)建變量時(shí)的內(nèi)存管理:

對(duì)于函數(shù)來(lái)說(shuō),正常情況下函數(shù)執(zhí)行完畢,其占用的內(nèi)存就會(huì)被垃圾回收:

function foo() {
    const obj = {name: '張三'}
    console.log(obj)
}
foo(); // 函數(shù)執(zhí)行完畢,obj作為局部變量,會(huì)隨著函數(shù)的結(jié)束而結(jié)束,{name: '張三'}由于零引用,其占用的內(nèi)存空間會(huì)被釋放

但是如果函數(shù)中存在全局引用,那么函數(shù)結(jié)束后,全局引用占用的內(nèi)存將無(wú)法被釋放

function foo() {
    const obj = {name: '張三'}
    window.obj = obj;
    console.log(obj)
}
foo(); // 函數(shù)執(zhí)行完畢,{name: '張三'}被全局引用

引用計(jì)數(shù)有一個(gè)缺陷,那就是無(wú)法處理循環(huán)引用。

循環(huán)引用

循環(huán)引用指的是兩個(gè)或者多個(gè)對(duì)象之間,存在相互引用,并形成了一個(gè)循環(huán)。如果是在函數(shù)中,函數(shù)運(yùn)行結(jié)束后應(yīng)該釋放掉所有局部變量引用的對(duì)象,但是按照引用計(jì)數(shù)算法,循環(huán)引用間并不是零引用,因此它們就不會(huì)被釋放。舉個(gè)例子:

function foo() {
    const obj = {name: '張三'};
    const obj2 = {age: 0};
    obj.a = obj2; // obj對(duì)象引用了obj2
    obj2.a = obj; // obj2引用了obj
}
foo(); // 由于存在循環(huán)引用,{name: '張三'}和{age: 0}所占用的堆內(nèi)存都不會(huì)被釋放

上面的例子可能比較抽象,我們?cè)賮?lái)舉一個(gè)實(shí)際的例子。在IE6、7版本中(IE已于2022年6月15日正式退出了歷史舞臺(tái)),在對(duì)DOM對(duì)象進(jìn)行垃圾回收時(shí),就有可能因?yàn)檠h(huán)引用導(dǎo)致內(nèi)存泄漏。

let div = document.getElementById('div1');
div.a = div; // 循環(huán)引用自己
div.someBigData = new Array(10000).fill('*');

在上述例子中,div對(duì)象的a屬性引用了div對(duì)象自身,造成了最簡(jiǎn)單的循環(huán)引用,并且該屬性并沒(méi)有被移除或者顯示設(shè)置為null,這對(duì)于引用計(jì)數(shù)器來(lái)說(shuō)就是一個(gè)有意義的引用。因此,div對(duì)象會(huì)一直保持在內(nèi)存中,即使在DOM樹(shù)中將div1刪除,而且div對(duì)象的someBigData所引用的數(shù)據(jù)也會(huì)一直保持在內(nèi)存中,不會(huì)被釋放。如果div對(duì)象本身很大,或者其屬性引用的數(shù)據(jù)很大,那么持續(xù)累積就可能造成內(nèi)存泄漏 。

標(biāo)記清除

標(biāo)記清除算法是對(duì)引用計(jì)數(shù)算法的改進(jìn),如果說(shuō)引用計(jì)數(shù)算法是判斷對(duì)象是否不再需要,那么標(biāo)記清楚算法就是判斷對(duì)象是否可以獲得??梢垣@得的對(duì)象就保留在內(nèi)存中,不可獲得的對(duì)象就會(huì)被垃圾回收。

垃圾回收并不是實(shí)時(shí)的,使用標(biāo)記清除算法的垃圾回收器,會(huì)定期從根對(duì)象開(kāi)始,在js中就是從window對(duì)象開(kāi)始,找出所有從根開(kāi)始引用的對(duì)象,以及找到這些對(duì)象引用的對(duì)象,直到全部遍歷。垃圾回收器就可以收集到所有可獲得的對(duì)象以及所有不可獲得的對(duì)象,然后將不可獲得的對(duì)象回收。

使用標(biāo)記清除算法可以有效解決引用計(jì)數(shù)算法的循環(huán)引用問(wèn)題,還是剛剛那個(gè)例子:

function foo() {
    const obj = {name: '張三'};
    const obj2 = {age: 0};
    obj.a = obj2; // obj對(duì)象引用了obj2
    obj2.a = obj; // obj2引用了obj
}
foo();

foo()函數(shù)執(zhí)行完畢后,垃圾回收器從window對(duì)象開(kāi)始找,發(fā)現(xiàn)obj和obj2是不可獲得的對(duì)象,那么其引用的數(shù)據(jù)就會(huì)被回收。我們簡(jiǎn)單修改一下代碼:

function foo() {
    const obj = {name: '張三'};
    const obj2 = {age: 0};
    obj.a = obj2; // obj對(duì)象引用了obj2
    obj2.a = obj; // obj2引用了obj
    window.obj = obj;
}
foo();
console.log(window.obj)

foo()函數(shù)執(zhí)行完畢,垃圾回收期從window對(duì)象開(kāi)始找,發(fā)現(xiàn)可以在window對(duì)象上找到obj屬性,obj和obj2存在循環(huán)引用,最終obj和obj2引用的數(shù)據(jù)都不會(huì)被垃圾回收。

這個(gè)例子也告訴我們,使用全局變量時(shí)一定要注意是否可能造成內(nèi)存泄漏,詳細(xì)可查看內(nèi)存泄漏的場(chǎng)景。使用標(biāo)記清楚算法就基本上能滿(mǎn)足垃圾回收的需求了,而且從2012年開(kāi)始,現(xiàn)代主流瀏覽器的垃圾回收器都實(shí)現(xiàn)了標(biāo)記清除算法,后續(xù)的改進(jìn)也是基于該算法來(lái)實(shí)現(xiàn)的。

閉包是內(nèi)存泄漏嗎

使用過(guò)閉包的都知道,其數(shù)據(jù)是保持在內(nèi)存中的,不會(huì)被回收,那么閉包是內(nèi)存泄漏嗎?答案:閉包不是內(nèi)存泄漏。因?yàn)槲覀冋f(shuō)的內(nèi)存泄漏是不符合預(yù)期的內(nèi)存持續(xù)增長(zhǎng),閉包雖然也會(huì)占著內(nèi)存不釋放,但是這個(gè)是符合我們預(yù)期的效果。

閉包不是內(nèi)存泄漏,難道就可以隨便使用了嗎。那肯定不是的,閉包中的數(shù)據(jù)如果很大,也會(huì)消耗大量的內(nèi)存,造成網(wǎng)頁(yè)卡頓,甚至崩潰。因此我們不能濫用閉包,在閉包函數(shù)退出前,一些不必要的局部變量該清除的還是要清除。

總結(jié)

本文詳細(xì)的解釋了什么是內(nèi)存泄漏,泄漏了該怎么檢測(cè),瀏覽器是怎么來(lái)進(jìn)行垃圾回收的,以及一些常見(jiàn)的內(nèi)存泄漏場(chǎng)景??偟膩?lái)說(shuō),內(nèi)存泄漏就是指發(fā)生非預(yù)期的內(nèi)存占用持續(xù)增長(zhǎng),以至于耗盡內(nèi)存,導(dǎo)致系統(tǒng)崩潰。內(nèi)存泄漏在實(shí)際開(kāi)發(fā)過(guò)程中還是比較容易犯的,在寫(xiě)代碼的時(shí)候一定要留意高發(fā)場(chǎng)景,盡可能在寫(xiě)代碼的時(shí)候就避免潛在的內(nèi)存泄漏,而不是等到系統(tǒng)崩潰了才來(lái)一句:重啟(刷新)大法好。

以上就是一文搞懂JavaScript中的內(nèi)存泄露的詳細(xì)內(nèi)容,更多關(guān)于JavaScript內(nèi)存泄露的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論