2021-4-8 前端達(dá)人
不知道在座的各位有沒有被問到過這樣一個(gè)問題:如果頁面卡頓,你覺得可能是什么原因造成的?有什么辦法鎖定原因并解決嗎?
這是一個(gè)非常寬泛而又有深度的問題,他涉及到很多的頁面性能優(yōu)化問題,我依稀還記得當(dāng)初面試被問到這個(gè)問題時(shí)我是這么回答的:
后來了解到了,感官上的長時(shí)間運(yùn)行頁面卡頓也有可能是因?yàn)?span style="box-sizing:border-box;outline:0px;--tw-shadow:0 0 #0000;--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(66, 153, 225, 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;user-select:text !important;font-weight:700;overflow-wrap:break-word;">內(nèi)存泄漏引起的
那什么是內(nèi)存泄漏呢?借助別的大佬給出的定義,內(nèi)存泄漏就是指由于疏忽或者程序的某些錯(cuò)誤造成未能釋放已經(jīng)不再使用的內(nèi)存的情況。簡單來講就是假設(shè)某個(gè)變量占用100M的內(nèi)存,而你又用不到這個(gè)變量,但是這個(gè)變量沒有被手動(dòng)的回收或自動(dòng)回收,即仍然占用100M的內(nèi)存空間,這就是一種內(nèi)存的浪費(fèi),即內(nèi)存泄漏
JavaScript
的內(nèi)存空間分為棧內(nèi)存和堆內(nèi)存,前者用來存放一些簡單變量,后者用來存放復(fù)雜對象
String
、Number
、Boolean
、null
、undefined
、Symbol
、BigInt
Object
、Array
、Function
…
根據(jù)內(nèi)存泄漏的定義,有些變量或數(shù)據(jù)不再被使用或不需要了,那么它就是垃圾變量或垃圾數(shù)據(jù),如果其一直保存在內(nèi)存中,最終可能會(huì)導(dǎo)致內(nèi)存占用過多的情況。那么此時(shí)就需要對這些垃圾數(shù)據(jù)進(jìn)行回收,這里引入了垃圾回收機(jī)制的概念
垃圾回收的機(jī)制分為手動(dòng)和自動(dòng)兩種
例如C/C++
采用的就是手動(dòng)回收的機(jī)制,即先用代碼為某個(gè)變量分配一定的內(nèi)存,然后在不需要了后,再用代碼手動(dòng)釋放掉內(nèi)存
而JavaScript
采用的則是自動(dòng)回收的機(jī)制,即我們不需要關(guān)心何時(shí)為變量分配多大的內(nèi)存,也不需要關(guān)心何時(shí)去釋放內(nèi)存,因?yàn)檫@一切都是自動(dòng)的。但這不表示我們不需要關(guān)心內(nèi)存的管理?。。?!否則也不會(huì)有本文討論的內(nèi)存泄露了
接下來就講一下JavaScript
的垃圾回收機(jī)制
通常全局狀態(tài)(window)下的變量是不會(huì)被自動(dòng)回收的,所以我們來討論一下局部作用域下的內(nèi)存回收情況
function fn1 () { let a = { name: '零一' } let b = 3 function fn2() { let c = [1, 2, 3] } fn2() return a } let res = fn1()
以上代碼的調(diào)用棧如下圖所示:
圖中左側(cè)為??臻g,用于存放一些執(zhí)行上下文和基本類型數(shù)據(jù);右側(cè)為堆空間,用于存放一些復(fù)雜對象數(shù)據(jù)
當(dāng)代碼執(zhí)行到fn2()
時(shí),??臻g內(nèi)的執(zhí)行上下文從上往下依次是 fn2函數(shù)執(zhí)行上下文 => fn1函數(shù)執(zhí)行上下文 => 全局執(zhí)行上下文
待fn2
函數(shù)內(nèi)部執(zhí)行完畢以后,就該退出fn2函數(shù)執(zhí)行上下文
了,即箭頭向下移動(dòng),此時(shí)fn2函數(shù)執(zhí)行上下文
會(huì)被清除并釋放棧內(nèi)存空間,如圖所示:
待fn1
函數(shù)內(nèi)部執(zhí)行完畢以后,就該退出fn1函數(shù)執(zhí)行上下文
了,即箭頭再向下移動(dòng),此時(shí)fn1函數(shù)執(zhí)行上下文
會(huì)被清除并釋放相應(yīng)的棧內(nèi)存空間,如圖所示:
此時(shí)處于全局的執(zhí)行上下文中。JavaScript
的垃圾回收器會(huì)每隔一段時(shí)間遍歷調(diào)用棧,假設(shè)此時(shí)觸發(fā)了垃圾回收機(jī)制,當(dāng)遍歷調(diào)用棧時(shí)發(fā)現(xiàn)變量b
和變量c
沒有被任何變量所引用,所以認(rèn)定它們是垃圾數(shù)據(jù)并給它們打上標(biāo)記。因?yàn)?code style="box-sizing:border-box;outline:0px;--tw-shadow:0 0 #0000;--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(66, 153, 225, 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;user-select:text !important;font-family:"font-size:14px;line-height:22px;color:#C7254E;background-color:#F9F2F4;border-radius:2px;padding:2px 4px;overflow-wrap:break-word;">fn1函數(shù)執(zhí)行完后將變量a
返回了出去,并存儲(chǔ)在全局變量res
中,所以認(rèn)定其為活動(dòng)數(shù)據(jù)并打上相應(yīng)標(biāo)記。待空閑時(shí)刻就會(huì)將標(biāo)記上垃圾數(shù)據(jù)的變量給全部清除掉,釋放相應(yīng)的內(nèi)存,如圖所示:
從這我們得出幾點(diǎn)結(jié)論:
JavaScript
的垃圾回收機(jī)制是自動(dòng)執(zhí)行的,并且會(huì)通過標(biāo)記來識(shí)別并清除垃圾數(shù)據(jù)
補(bǔ)充: JavaScript
的垃圾回收機(jī)制有著很多的步驟,上述只講到了標(biāo)記-清除
,其實(shí)還有其它的過程,這里簡單介紹一下就不展開討論了。例如:標(biāo)記-整理
,在清空部分垃圾數(shù)據(jù)后釋放了一定的內(nèi)存空間后會(huì)可能會(huì)留下大面積的不連續(xù)內(nèi)存片段,導(dǎo)致后續(xù)可能無法為某些對象分配連續(xù)內(nèi)存,此時(shí)需要整理一下內(nèi)存空間;交替執(zhí)行
,因?yàn)?code style="box-sizing:border-box;outline:0px;--tw-shadow:0 0 #0000;--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(66, 153, 225, 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;user-select:text !important;font-family:"font-size:14px;line-height:22px;color:#C7254E;background-color:#F9F2F4;border-radius:2px;padding:2px 4px;overflow-wrap:break-word;">JavaScript是運(yùn)行在主線程上的,所以執(zhí)行垃圾回收機(jī)制時(shí)會(huì)暫停js
的運(yùn)行,若垃圾回收執(zhí)行時(shí)間過長,則會(huì)給用戶帶來明顯的卡頓現(xiàn)象,所以垃圾回收機(jī)制會(huì)被分成一個(gè)個(gè)的小任務(wù),穿插在js
任務(wù)之中,即交替執(zhí)行,盡可能得保證不會(huì)帶來明顯的卡頓感
在了解一些常見的內(nèi)存泄漏的場景之前,先簡單介紹一下如何使用Chrome
的開發(fā)者工具來查看js
內(nèi)存情況
首先打開Chrome
的無痕模式,這樣做的目的是為了屏蔽掉Chrome
插件對我們之后測試內(nèi)存占用情況的影響
然后打開開發(fā)者工具
,找到Performance
這一欄,可以看到其內(nèi)部帶著一些功能按鈕,例如:開始錄制按鈕;刷新頁面按鈕;清空記錄按鈕;記錄并可視化js內(nèi)存、節(jié)點(diǎn)、事件監(jiān)聽器按鈕;觸發(fā)垃圾回收機(jī)制按鈕等等
簡單錄制一下百度頁面,看看我們能獲得什么,如下動(dòng)圖所示:
從上圖中我們可以看到,在頁面從零到加載完成這個(gè)過程中JS Heap(js堆內(nèi)存)
、documents(文檔)
、Nodes(DOM節(jié)點(diǎn))
、Listeners(監(jiān)聽器)
、GPU memory(GPU內(nèi)存)
的最低值、最高值以及隨時(shí)間的走勢曲線,這也是我們主要關(guān)注的點(diǎn)
再來看看開發(fā)者工具中的Memory
一欄,其主要是用于記錄頁面堆內(nèi)存的具體情況以及js
堆內(nèi)存隨加載時(shí)間線動(dòng)態(tài)的分配情況
堆快照就像照相機(jī)一樣,能記錄你當(dāng)前頁面的堆內(nèi)存情況,每快照一次就會(huì)產(chǎn)生一條快照記錄,如圖所示:
如上圖所示,剛開始執(zhí)行了一次快照,記錄了當(dāng)時(shí)堆內(nèi)存空間占用為13.9MB
,然后我們點(diǎn)擊了頁面中某些按鈕,又執(zhí)行一次快照,記錄了當(dāng)時(shí)堆內(nèi)存空間占用為13.4MB
。并且點(diǎn)擊對應(yīng)的快照記錄,能看到當(dāng)時(shí)所有內(nèi)存中的變量情況(結(jié)構(gòu)、占總占用內(nèi)存的百分比…)
然后我們還可以看一下頁面動(dòng)態(tài)的內(nèi)存變化情況,如圖所示:
在開始記錄后,我們可以看到圖中右上角有起伏的藍(lán)色與灰色的柱形圖,其中藍(lán)色表示當(dāng)前時(shí)間線下占用著的內(nèi)存;灰色表示之前占用的內(nèi)存空間已被清除釋放。
從上圖過程來看,我們可以看到剛開始處于的tab
所對應(yīng)顯示的頁面中占用了一定的堆內(nèi)存空間,成藍(lán)色柱形,在點(diǎn)擊別的tab
后,原tab
對應(yīng)的內(nèi)容消失,并且原來藍(lán)色的柱形變成灰色(表示原占用的內(nèi)存空間得到了釋放),同時(shí)新tab
所對應(yīng)顯示的頁面也占用了一定的堆內(nèi)存空間。因此后續(xù)我們就可以針對這個(gè)圖來查看內(nèi)存的占用與清除情況
那么到底有哪些情況會(huì)出現(xiàn)內(nèi)存泄漏的情況呢?這里列舉了常見的幾種:
接下來介紹一下各種情況,并嘗試用剛才講到的兩種方法來捕捉問題所在
文章開頭的例子中,在退出fn1函數(shù)執(zhí)行上下文
后,該上下文中的變量a
本應(yīng)被當(dāng)作垃圾數(shù)據(jù)給回收掉,但因fn1
函數(shù)最終將變量a
返回并賦值給全局變量res
,其產(chǎn)生了對變量a
的引用,所以變量a
被標(biāo)記為活動(dòng)變量并一直占用著相應(yīng)的內(nèi)存,假設(shè)變量res
后續(xù)用不到,這就算是一種閉包使用不當(dāng)?shù)睦?
接下來嘗試使用Performance
和Memory
來查看一下閉包導(dǎo)致的內(nèi)存泄漏問題,為了使內(nèi)存泄漏的結(jié)果更加明顯,我們稍微改動(dòng)一下文章開頭的例子,代碼如下:
<button onclick="myClick()">執(zhí)行fn1函數(shù)</button> <script> function fn1 () { let a = new Array(10000) // 這里設(shè)置了一個(gè)很大的數(shù)組對象 let b = 3 function fn2() { let c = [1, 2, 3] } fn2() return a } let res = [] function myClick() { res.push(fn1()) } </script>
設(shè)置了一個(gè)按鈕,每次執(zhí)行就會(huì)將fn1
函數(shù)的返回值添加到全局?jǐn)?shù)組變量res
中,是為了能在performacne
的曲線圖中看出效果,如圖所示:
在每次錄制開始時(shí)手動(dòng)觸發(fā)一次垃圾回收機(jī)制,這是為了確認(rèn)一個(gè)初始的堆內(nèi)存基準(zhǔn)線,便于后面的對比,然后我們點(diǎn)擊了幾次按鈕,即往全局?jǐn)?shù)組變量res
中添加了幾個(gè)比較大的數(shù)組對象,最后再觸發(fā)一次垃圾回收,發(fā)現(xiàn)錄制結(jié)果的JS Heap
曲線剛開始成階梯式上升的,最后的曲線的高度比基準(zhǔn)線要高,說明可能是存在內(nèi)存泄漏的問題
在得知有內(nèi)存泄漏的情況存在時(shí),我們可以改用Memory
來更明確得確認(rèn)問題和定位問題
首先可以用Allocation instrumentation on timeline
來確認(rèn)問題,如下圖所示:
在我們每次點(diǎn)擊按鈕后,動(dòng)態(tài)內(nèi)存分配情況圖上都會(huì)出現(xiàn)一個(gè)藍(lán)色的柱形,并且在我們觸發(fā)垃圾回收后,藍(lán)色柱形都沒變成灰色柱形,即之前分配的內(nèi)存并未被清除
所以此時(shí)我們就可以更明確得確認(rèn)內(nèi)存泄漏的問題是存在的了,接下來就精準(zhǔn)定位問題,可以利用Heap snapshot
來定位問題,如圖所示:
第一次先點(diǎn)擊快照記錄初始的內(nèi)存情況,然后我們多次點(diǎn)擊按鈕后再次點(diǎn)擊快照,記錄此時(shí)的內(nèi)存情況,發(fā)現(xiàn)從原來的1.1M
內(nèi)存空間變成了1.4M
內(nèi)存空間,然后我們選中第二條快照記錄,可以看到右上角有個(gè)All objects
的字段,其表示展示的是當(dāng)前選中的快照記錄所有對象的分配情況,而我們想要知道的是第二條快照與第一條快照的區(qū)別在哪,所以選擇Object allocated between Snapshot1 and Snapshot2
,即展示第一條快照和第二條快照存在差異的內(nèi)存對象分配情況,此時(shí)可以看到Array
的百分比很高,初步可以判斷是該變量存在問題,點(diǎn)擊查看詳情后就能查看到該變量對應(yīng)的具體數(shù)據(jù)了
以上就是一個(gè)判斷閉包帶來內(nèi)存泄漏問題并簡單定位的方法了
全局的變量一般是不會(huì)被垃圾回收掉的,在文章開頭也提到過了。當(dāng)然這并不是說變量都不能存在全局,只是有時(shí)候會(huì)因?yàn)槭韬龆鴮?dǎo)致某些變量流失到全局,例如未聲明變量,卻直接對某變量進(jìn)行賦值,就會(huì)導(dǎo)致該變量在全局創(chuàng)建,如下所示:
function fn1() { // 此處變量name未被聲明 name = new Array(99999999) } fn1()
此時(shí)這種情況就會(huì)在全局自動(dòng)創(chuàng)建一個(gè)變量name
,并將一個(gè)很大的數(shù)組賦值給name
,又因?yàn)槭侨肿兞?,所以該?nèi)存空間就一直不會(huì)被釋放
解決辦法的話,自己平時(shí)要多加注意,不要在變量未聲明前賦值,或者也可以開啟嚴(yán)格模式,這樣就會(huì)在不知情犯錯(cuò)時(shí),收到報(bào)錯(cuò)警告,例如:
function fn1() { 'use strict'; name = new Array(99999999) } fn1()
什么叫DOM節(jié)點(diǎn)?假設(shè)你手動(dòng)移除了某個(gè)dom
節(jié)點(diǎn),本應(yīng)釋放該dom
節(jié)點(diǎn)所占用的內(nèi)存,但卻因?yàn)槭韬鰧?dǎo)致某處代碼仍對該被移除節(jié)點(diǎn)有引用,最終導(dǎo)致該節(jié)點(diǎn)所占內(nèi)存無法被釋放,例如這種情況:
改動(dòng)很簡單,就是將對.child
節(jié)點(diǎn)的引用移動(dòng)到了click
事件的回調(diào)函數(shù)中,那么當(dāng)移除節(jié)點(diǎn)并退出回調(diào)函數(shù)的執(zhí)行上文后就會(huì)自動(dòng)清除對該節(jié)點(diǎn)的引用,那么自然就不會(huì)存在內(nèi)存泄漏的情況了,我們來驗(yàn)證一下,如下圖所示:
結(jié)果很明顯,這樣處理過后就不存在內(nèi)存泄漏的情況了
控制臺(tái)的打印也會(huì)造成內(nèi)存泄漏嗎????是的呀,如果瀏覽器不一直保存著我們打印對象的信息,我們?yōu)楹文茉诿看未蜷_控制的Console
時(shí)看到具體的數(shù)據(jù)呢?先來看一段測試代碼:
<button>按鈕</button> <script> document.querySelector('button').addEventListener('click', function() { let obj = new Array(1000000) console.log(obj); }) </script>
我們在按鈕的點(diǎn)擊回調(diào)事件中創(chuàng)建了一個(gè)很大的數(shù)組對象并打印,用performance
來驗(yàn)證一下:
開始錄制,先觸發(fā)一次垃圾回收清除初始的內(nèi)存,然后點(diǎn)擊三次按鈕,即執(zhí)行了三次點(diǎn)擊事件,最后再觸發(fā)一次垃圾回收。查看錄制結(jié)果發(fā)現(xiàn)JS Heap
曲線成階梯上升,并且最終保持的高度比初始基準(zhǔn)線高很多,這說明每次執(zhí)行點(diǎn)擊事件創(chuàng)建的很大的數(shù)組對象obj
都因?yàn)?code style="box-sizing:border-box;outline:0px;--tw-shadow:0 0 #0000;--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(66, 153, 225, 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;user-select:text !important;font-family:"font-size:14px;line-height:22px;color:#C7254E;background-color:#F9F2F4;border-radius:2px;padding:2px 4px;overflow-wrap:break-word;">console.log被瀏覽器保存了下來并且無法被回收
接下來注釋掉console.log
,再來看一下結(jié)果:
<button>按鈕</button> <script> document.querySelector('button').addEventListener('click', function() { let obj = new Array(1000000) // console.log(obj); }) </script>
performance
如圖所示:
可以看到?jīng)]有打印以后,每次創(chuàng)建的obj
都立馬被銷毀了,并且最終觸發(fā)垃圾回收機(jī)制后跟初始的基準(zhǔn)線同樣高,說明已經(jīng)不存在內(nèi)存泄漏的現(xiàn)象了
其實(shí)同理,console.log
也可以用Memory
來進(jìn)一步驗(yàn)證
console.log
console.log
最后簡單總結(jié)一下:在開發(fā)環(huán)境下,可以使用控制臺(tái)打印便于調(diào)試,但是在生產(chǎn)環(huán)境下,盡可能得不要在控制臺(tái)打印數(shù)據(jù)。所以我們經(jīng)常會(huì)在代碼中看到類似如下的操作:
// 如果在開發(fā)環(huán)境下,打印變量obj if(isDev) { console.log(obj) }
這樣就避免了生產(chǎn)環(huán)境下無用的變量打印占用一定的內(nèi)存空間,同樣的除了console.log
之外,console.error
、console.info
、console.dir
等等都不要在生產(chǎn)環(huán)境下使用
其實(shí)定時(shí)器也是平時(shí)很多人會(huì)忽略的一個(gè)問題,比如定義了定時(shí)器后就再也不去考慮清除定時(shí)器了,這樣其實(shí)也會(huì)造成一定的內(nèi)存泄漏。來看一個(gè)代碼示例:
<button>開啟定時(shí)器</button> <script> function fn1() { let largeObj = new Array(100000) setInterval(() => { let myObj = largeObj }, 1000) } document.querySelector('button').addEventListener('click', function() { fn1() }) </script>
這段代碼是在點(diǎn)擊按鈕后執(zhí)行fn1
函數(shù),fn1
函數(shù)內(nèi)創(chuàng)建了一個(gè)很大的數(shù)組對象largeObj
,同時(shí)創(chuàng)建了一個(gè)setInterval
定時(shí)器,定時(shí)器的回調(diào)函數(shù)只是簡單的引用了一下變量largeObj
,我們來看看其整體的內(nèi)存分配情況吧:
按道理來說點(diǎn)擊按鈕執(zhí)行fn1
函數(shù)后會(huì)退出該函數(shù)的執(zhí)行上下文,緊跟著函數(shù)體內(nèi)的局部變量應(yīng)該被清除,但圖中performance
的錄制結(jié)果顯示似乎是存在內(nèi)存泄漏問題的,即最終曲線高度比基準(zhǔn)線高度要高,那么再用Memory
來確認(rèn)一次:
在我們點(diǎn)擊按鈕后,從動(dòng)態(tài)內(nèi)存分配的圖上看到出現(xiàn)一個(gè)藍(lán)色柱形,說明瀏覽器為變量largeObj
分配了一段內(nèi)存,但是之后這段內(nèi)存并沒有被釋放掉,說明的確存在內(nèi)存泄漏的問題,原因其實(shí)就是因?yàn)?code style="box-sizing:border-box;outline:0px;--tw-shadow:0 0 #0000;--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(66, 153, 225, 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;user-select:text !important;font-family:"font-size:14px;line-height:22px;color:#C7254E;background-color:#F9F2F4;border-radius:2px;padding:2px 4px;overflow-wrap:break-word;">setInterval的回調(diào)函數(shù)內(nèi)對變量largeObj
有一個(gè)引用關(guān)系,而定時(shí)器一直未被清除,所以變量largeObj
的內(nèi)存也自然不會(huì)被釋放
那么我們?nèi)绾蝸斫鉀Q這個(gè)問題呢,假設(shè)我們只需要讓定時(shí)器執(zhí)行三次就可以了,那么我們可以改動(dòng)一下代碼:
<button>開啟定時(shí)器</button> <script> function fn1() { let largeObj = new Array(100000) let index = 0 let timer = setInterval(() => { if(index === 3) clearInterval(timer); let myObj = largeObj
index ++ }, 1000) } document.querySelector('button').addEventListener('click', function() { fn1() }) </script>
現(xiàn)在我們再通過performance
和memory
來看看還不會(huì)存在內(nèi)存泄漏的問題
這次的錄制結(jié)果就能看出,最后的曲線高度和初始基準(zhǔn)線的高度一樣,說明并沒有內(nèi)存泄漏的情況
這里做一個(gè)解釋,圖中剛開始出現(xiàn)的藍(lán)色柱形是因?yàn)槲以阡浿坪笏⑿铝隧撁?,可以忽略;然后我們點(diǎn)擊了按鈕,看到又出現(xiàn)了一個(gè)藍(lán)色柱形,此時(shí)就是為fn1
函數(shù)中的變量largeObj
分配了內(nèi)存,3s
后該內(nèi)存又被釋放了,即變成了灰色柱形。所以我們可以得出結(jié)論,這段代碼不存在內(nèi)存泄漏的問題
簡單總結(jié)一下: 大家在平時(shí)用到了定時(shí)器,如果在用不到定時(shí)器后一定要清除掉,否則就會(huì)出現(xiàn)本例中的情況。除了setTimeout
和setInterval
,其實(shí)瀏覽器還提供了一個(gè)API也可能就存在這樣的問題,那就是requestAnimationFrame
在項(xiàng)目過程中,如果遇到了某些性能問題可能跟內(nèi)存泄漏有關(guān)時(shí),就可以參照本文列舉的5
種情況去排查,一定能找到問題所在并給到解決辦法的。
雖然JavaScript
的垃圾回收是自動(dòng)的,但我們有時(shí)也是需要考慮要不要手動(dòng)清除某些變量的內(nèi)存占用的,例如你明確某個(gè)變量在一定條件下再也不需要,但是還會(huì)被外部變量引用導(dǎo)致內(nèi)存無法得到釋放時(shí),你可以用null
對該變量重新賦值就可以在后續(xù)垃圾回收階段釋放該變量的內(nèi)存了。
轉(zhuǎn)自:csdn博客 作者:「零一」
藍(lán)藍(lán)設(shè)計(jì)( m.yvirxh.cn )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)
藍(lán)藍(lán)設(shè)計(jì)的小編 http://m.yvirxh.cn