摘要:本文主要選取了這篇文章中的一小部分來說明一下中產(chǎn)生內(nèi)存泄漏的常見情況對于較難理解的第四種情況參考了一些文章來進(jìn)行說明意外的全局變量中如果不用聲明變量該變量將被視為對象全局對象的屬性也就是全局變量上面的函數(shù)等價于所以你調(diào)用完了函數(shù)以后變量仍然
本文主要選取了4 Types of Memory Leaks in JavaScript and How to Get Rid Of Them 這篇文章中的一小部分來說明一下js中產(chǎn)生內(nèi)存泄漏的常見情況. 對于較難理解的第四種情況, 參考了一些文章來進(jìn)行說明.
意外的全局變量js中如果不用var聲明變量,該變量將被視為window對象(全局對象)的屬性,也就是全局變量.
function foo(arg) { bar = "this is a hidden global variable"; } // 上面的函數(shù)等價于 function foo(arg) { window.bar = "this is an explicit global variable"; }
所以,你調(diào)用完了函數(shù)以后,變量仍然存在,導(dǎo)致泄漏.
如果不注意this的話,還可能會這么漏:
function foo() { this.variable = "potential accidental global"; } // 沒有對象調(diào)用foo, 也沒有給它綁定this, 所以this是window foo();
你可以通過加上"use strict"啟用嚴(yán)格模式來避免這類問題, 嚴(yán)格模式會組織你創(chuàng)建意外的全局變量.
被遺忘的定時器或者回調(diào)var someResource = getData(); setInterval(function() { var node = document.getElementById("Node"); if(node) { node.innerHTML = JSON.stringify(someResource)); } }, 1000);
這樣的代碼很常見, 如果id為Node的元素從DOM中移除, 該定時器仍會存在, 同時, 因為回調(diào)函數(shù)中包含對someResource的引用, 定時器外面的someResource也不會被釋放.
沒有清理的DOM元素引用var elements = { button: document.getElementById("button"), image: document.getElementById("image"), text: document.getElementById("text") }; function doStuff() { image.src = "http://some.url/image"; button.click(); console.log(text.innerHTML); } function removeButton() { document.body.removeChild(document.getElementById("button")); // 雖然我們用removeChild移除了button, 但是還在elements對象里保存著#button的引用 // 換言之, DOM元素還在內(nèi)存里面. }閉包
先看這樣一段代碼:
var theThing = null; var replaceThing = function () { var someMessage = "123" theThing = { someMethod: function () { console.log(someMessage); } }; };
調(diào)用replaceThing之后, 調(diào)用theThing.someMethod, 會輸出123, 基本的閉包, 我想到這里應(yīng)該不難理解.
解釋一下的話, theThing包含一個someMethod方法, 該方法引用了函數(shù)中的someMessage變量, 所以函數(shù)中的someMessage變量不會被回收, 調(diào)用someMethod可以拿到它正確的console.log出來.
接下來我這么改一下:
var theThing = null; var replaceThing = function () { var originalThing = theThing; var someMessage = "123" theThing = { longStr: new Array(1000000).join("*"), // 大概占用1MB內(nèi)存 someMethod: function () { console.log(someMessage); } }; };
我們先做一個假設(shè), 如果函數(shù)中所有的私有變量, 不管someMethod用不用, 都被放進(jìn)閉包的話, 那么會發(fā)生什么呢.
第一次調(diào)用replaceThing, 閉包中包含originalThing = null和someMessage = "123", 我們設(shè)函數(shù)結(jié)束時, theThing的值為theThing_1.
第二次調(diào)用replaceThing, 如果我們的假設(shè)成立, originalThing = theThing_1和someMessage = "123".我們設(shè)第二次調(diào)用函數(shù)結(jié)束時, theThing的值為theThing_2.注意, 此時的originalThing保存著theThing_1, theThing_1包含著和theThing_2截然不同的someMethod, theThing_1的someMethod中包含一個someMessage, 同樣如果我們的假設(shè)成立, 第一次的originalThing = null應(yīng)該也在.
所以, 如果我們的假設(shè)成立, 第二次調(diào)用以后, 內(nèi)存中有theThing_1和theThing_2, 因為他們都是靠longStr把占用內(nèi)存撐起來, 所以第二次調(diào)用以后, 內(nèi)存消耗比第一次多1MB.
如果你親自試了(使用Chrome的Profiles查看每次調(diào)用后的內(nèi)存快照), 會發(fā)現(xiàn)我們的假設(shè)是不成立的, 瀏覽器很聰明, 它只會把someMethod用到的變量保存下來, 用不到的就不保存了, 這為我們節(jié)省了內(nèi)存.
但如果我們這么寫:
var theThing = null; var replaceThing = function () { var originalThing = theThing; var unused = function () { if (originalThing) console.log("hi"); }; var someMessage = "123" theThing = { longStr: new Array(1000000).join("*"), someMethod: function () { console.log(someMessage); } }; };
unused這個函數(shù)我們沒有用到, 但是它用了originalThing變量, 接下來, 如果你一次次調(diào)用replaceThing, 你會看到內(nèi)存1MB 1MB的漲.
也就是說, 雖然我們沒有使用unused, 但是因為它使用了originalThing, 使得它也被放進(jìn)閉包了, 內(nèi)存漏了.
強(qiáng)烈建議讀者親自試試在這幾種情況下產(chǎn)生的內(nèi)存變化.
這種情況產(chǎn)生的原因, 通俗講, 是因為無論someMethod還是unused, 他們其中所需要用到的在replaceThing中定義的變量是保存在一起的, 所以就漏了.
如果我沒有說明第四種情況, 可以參考以下鏈接, 或是在評論區(qū)評論.
參考鏈接An interesting kind of JavaScript memory leak
一個意想不到的Javascript內(nèi)存泄漏
Grokking V8 closures for fun (and profit?)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/79146.html
摘要:原文地址游客前言金三銀四,很多同學(xué)心里大概都準(zhǔn)備著年后找工作或者跳槽。最近有很多同學(xué)都在交流群里求大廠面試題。 最近整理了一波面試題,包括安卓JAVA方面的,目前大廠還是以安卓源碼,算法,以及數(shù)據(jù)結(jié)構(gòu)為主,有一些中小型公司也會問到混合開發(fā)的知識,至于我為什么傾向于混合開發(fā),我的一句話就是走上編程之路,將來你要學(xué)不僅僅是這些,豐富自己方能與世接軌,做好全棧的裝備。 原文地址:游客kutd...
摘要:本文將會討論中的內(nèi)存泄漏以及如何處理,方便大家在使用編碼時,更好的應(yīng)對內(nèi)存泄漏帶來的問題。當(dāng)內(nèi)存不再需要時進(jìn)行釋放大部分內(nèi)存泄漏問題都是在這個階段產(chǎn)生的,這個階段最難的問題就是確定何時不再需要已分配的內(nèi)存。中的相同對象稱為全局。 隨著現(xiàn)在的編程語言功能越來越成熟、復(fù)雜,內(nèi)存管理也容易被大家忽略。本文將會討論JavaScript中的內(nèi)存泄漏以及如何處理,方便大家在使用JavaScript...
摘要:如果這個靜態(tài)變量在生命周期結(jié)束后沒有清空,就導(dǎo)致內(nèi)存泄漏。因此造成內(nèi)存泄露。注冊沒取消造成的內(nèi)存泄露這種的內(nèi)存泄露比純的內(nèi)存泄漏還要嚴(yán)重,因為其他一些程序可能引用系統(tǒng)的程序的對象比如注冊機(jī)制。 原文鏈接 更多教程 為什么會發(fā)生內(nèi)存泄漏 內(nèi)存空間使用完畢之后未回收, 會導(dǎo)致內(nèi)存泄漏。有人會問:Java不是有垃圾自動回收機(jī)制么?不幸的是,在Java中仍存在很多容易導(dǎo)致內(nèi)存泄漏的邏輯(...
閱讀 1987·2021-09-22 15:45
閱讀 1767·2019-08-30 15:55
閱讀 1915·2019-08-29 11:16
閱讀 3391·2019-08-26 11:44
閱讀 823·2019-08-23 17:58
閱讀 2767·2019-08-23 12:25
閱讀 1723·2019-08-22 17:15
閱讀 3752·2019-08-22 16:09