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