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