Javascript有沒有內(nèi)存泄露?如果有,如何避免?鑒于最近有好幾個(gè)人問到我類似的問題,看來大家對(duì)這部分內(nèi)容還沒有系統(tǒng)的研究過,因此,打算在這里把個(gè)人幾年前整理的一些資料和大家分享一下。
首先,可以肯定的說,javascript的一些寫法會(huì)造成內(nèi)存泄露的,至少在IE6下如此。因此,在IE6遲遲不肯退休的今天,我們還是有必要了解相關(guān)的知識(shí)(雖然大部分情況下,js造成的這點(diǎn)內(nèi)存泄露不是致使電腦運(yùn)行變慢的主要原因)。相關(guān)的研究主要集中在05-07這幾年,本文并沒有什么新的觀點(diǎn),如果當(dāng)年有研究過的朋友,可以直接忽略。
作為前端開發(fā)人員,了解這些問題的時(shí)候,需要知其然也知其所以然,因此,在介紹js內(nèi)存泄露前,我們先從為什么會(huì)有內(nèi)存泄露談起。
說道內(nèi)存泄露,就不得不談到內(nèi)存分配的方式。內(nèi)存分配有三種方式,分別是:
一、靜態(tài)分配( Static Allocation ):靜態(tài)變量和全局變量的分配形式。如果把房間看做一個(gè)程序,我們可以把靜態(tài)分配的內(nèi)存當(dāng)成是房間里的耐用家具。通常,它們無需釋放和回收,因?yàn)闆]人會(huì)天天把大衣柜當(dāng)作垃圾扔到窗外。
二、自動(dòng)分配( Automatic Allocation ):在棧中為局部變量分配內(nèi)存的方法。棧中的內(nèi)存可以隨著代碼塊退出時(shí)的出棧操作被自動(dòng)釋放。
這類似于到房間中辦事的人,事情一旦完成,就會(huì)自己離開,而他們所占用的空間,也隨著這些人的離開而自動(dòng)釋放了。
三、動(dòng)態(tài)分配( Dynamic Allocation ):在堆中動(dòng)態(tài)分配內(nèi)存空間以存儲(chǔ)數(shù)據(jù)的方式。也就是程序運(yùn)行時(shí)用malloc或new申請(qǐng)的內(nèi)存,我們需要自己用free或delete釋放。動(dòng)態(tài)內(nèi)存的生存期由程序員自己決定。一旦忘記釋放,勢(shì)必造成內(nèi)存泄露。這種情況下,堆中的內(nèi)存塊好像我們?nèi)粘J褂玫牟徒砑,用過了就得扔到垃圾箱里,否則屋內(nèi)就會(huì)滿地狼藉。因此,懶人們做夢(mèng)都想有一臺(tái)家用機(jī)器人跟在身邊打掃衛(wèi)生。在軟件開發(fā)中,如果你懶得釋放內(nèi)存,那么你也需要一臺(tái)類似的機(jī)器人——這其實(shí)就是一個(gè)由特定算法實(shí)現(xiàn)的垃圾收集器。而正是垃圾收集機(jī)制本身的一些缺陷,導(dǎo)致了javascript內(nèi)存泄露。
幾年前看過一篇叫《垃圾回收趣史》的文章,里面對(duì)垃圾回收機(jī)制進(jìn)行了深入淺出的說明。
就像機(jī)械增壓這種很多豪車作為賣點(diǎn)的技術(shù),其實(shí)上個(gè)世紀(jì)10年代奔馳就在使用了一樣,垃圾回收技術(shù)誕生也有很長(zhǎng)的時(shí)間了。1960 年前后誕生于 MIT 的 Lisp 語言是第一種高度依賴于動(dòng)態(tài)內(nèi)存分配技術(shù)的語言,Lisp 中幾乎所有數(shù)據(jù)都以“表”的形式出現(xiàn),而“表”所占用的空間則是在堆中動(dòng)態(tài)分配得到的。 Lisp 語言先天就具有的動(dòng)態(tài)內(nèi)存管理特性要求 Lisp 語言的設(shè)計(jì)者必須解決堆中每一個(gè)內(nèi)存塊的自動(dòng)釋放問題(否則, Lisp 程序員就必然被程序中不計(jì)其數(shù)的 free 或 delete 語句淹沒),這直接導(dǎo)致了垃圾收集技術(shù)的誕生和發(fā)展。
而三種最基本的垃圾回收算法,也在那個(gè)時(shí)候一起出現(xiàn)了。下面我們一個(gè)一個(gè)了解一下:
引用計(jì)數(shù)(Reference Counting)算法:這個(gè)可能是最早想到的方法。形象點(diǎn)說,引用計(jì)數(shù)可以這么理解,房子里放了很多白紙,這些紙就好比是內(nèi)存。使用內(nèi)存,就好比在這些紙上寫字。內(nèi)存可以隨便使用,但是,有個(gè)條件,任何使用一張紙的人,必須在紙的一角寫上計(jì)數(shù)1,如果2個(gè)人同時(shí)使用一張紙,那么計(jì)數(shù)就變成2,以此類推。當(dāng)一個(gè)人使用完某張紙的時(shí)候,必須把角上的計(jì)數(shù)減1,這樣,一旦當(dāng)計(jì)數(shù)變?yōu)?,就滿足了垃圾回收條件,等在一旁的機(jī)器人會(huì)立即把這張紙扔進(jìn)垃圾箱。基于引用計(jì)數(shù)器的垃圾收集器運(yùn)行較快,不會(huì)長(zhǎng)時(shí)間中斷程序執(zhí)行,適宜地必須 實(shí)時(shí)運(yùn)行的程序。但引用計(jì)數(shù)器增加了程序執(zhí)行的開銷;同時(shí),還有個(gè)最大的問題,這個(gè)算法存在一個(gè)缺陷,就是一旦產(chǎn)生循環(huán)引用,內(nèi)存就會(huì)被泄露。舉個(gè)例子,我們new了2個(gè)對(duì)象a和b,這時(shí),a和b的計(jì)數(shù)都是1,然后,我們把a(bǔ)的一個(gè)屬性指向b,b的一個(gè)屬性指向a,此時(shí),由于引用的關(guān)系,a和b的計(jì)數(shù)都變成了2,當(dāng)程序運(yùn)行結(jié)束時(shí),退出作用域,程序自動(dòng)把a(bǔ)的計(jì)數(shù)減1,由于最后a的計(jì)數(shù)仍然為1,因此,a不會(huì)被釋放,同樣,b最后的計(jì)數(shù)也為1,b也不會(huì)被釋放,內(nèi)存就這么泄露了!
出處:alibaba.com中國(guó)站
責(zé)任編輯:bluehearts
上一頁 下一頁 GC與JS內(nèi)存泄露 [2]
◎進(jìn)入論壇網(wǎng)頁制作、WEB標(biāo)準(zhǔn)化版塊參加討論,我還想發(fā)表評(píng)論。
|