JavaScript :memory leak [轉]

来源:http://www.cnblogs.com/f1194361820/archive/2017/01/11/6273070.html
-Advertisement-
Play Games

Memory leak patterns in JavaScript Handling circular references in JavaScript applications Abhijeet Bhattacharya and Kiran Shivarama SundarPublished o ...


Memory leak patterns in JavaScript

Handling circular references in JavaScript applications

Abhijeet Bhattacharya and Kiran Shivarama Sundar
Published on April 24, 2007

Linked InGoogle+

Comments   6

JavaScript is a powerful scripting language used to add dynamic content to Web pages. It is especially beneficial for everyday tasks such as password validation and creating dynamic menu components. While JavaScript is easy to learn and write, it is prone to memory leaks in certain browsers. In this introductory article we explain what causes memory leaks in JavaScript, demonstrate some of the common memory leak patterns to watch out for, and show you how to work around them.

Note that the article assumes you are familiar with using JavaScript and DOM elements to develop Web applications. The article will be most useful to developers who use JavaScript for Web application development. It might also serve as a reference for those providing browser support to clients rolling out Web applications or for anyone tasked with troubleshooting browser issues.

Is my browser leaking?

Internet Explorer and Mozilla Firefox are the two Web browsers most commonly associated with memory leaks in JavaScript. The culprit in both browsers is the component object model used to manage DOM objects. Both the native Windows COM and Mozilla's XPCOM use reference-counting garbage collection for memory allocation and retrieval. Reference counting is not always compatible with the mark-and-sweep garbage collection used for JavaScript. This article focuses on ways to work around memory leaks in JavaScript code. SeeRelated topics to learn more about COM layer memory handling in Firefox and IE.

Memory leaks in JavaScript

JavaScript is a garbage collected language, meaning that memory is allocated to objects upon their creation and reclaimed by the browser when there are no more references to them. While there is nothing wrong with JavaScript's garbage collection mechanism, it is at odds with the way some browsers handle the allocation and recovery of memory for DOM objects.

Internet Explorer and Mozilla Firefox are two browsers that use reference counting to handle memory for DOM objects. In a reference counting system, each object referenced maintains a count of how many objects are referencing it. If the count becomes zero, the object is destroyed and the memory is returned to the heap. Although this solution is generally very efficient, it has a blind spot when it comes to circular (or cyclic) references.

What's wrong with circular references?

A circular reference is formed when two objects reference each other, giving each object a reference count of 1. In a purely garbage collected system, a circular reference is not a problem: If neither of the objects involved is referenced by any other object, then both are garbage collected. In a reference counting system, however, neither of the objects can be destroyed, because the reference count never reaches zero. In a hybrid system, where both garbage collection and reference counting are being used, leaks occur because the system fails to identify a circular reference. In this case, neither the DOM object nor the JavaScript object is destroyed. Listing 1 shows a circular reference between a JavaScript object and a DOM object.

Listing 1. A circular reference resulting in a memory leak
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html>     <body>     <script type="text/javascript">     document.write("Circular references between JavaScript and DOM!");     var obj;     window.onload = function(){     obj=document.getElementById("DivElement");             document.getElementById("DivElement").expandoProperty=obj;             obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));             };     </script>     <div id="DivElement">Div Element</div>     </body>     </html>

As you can see in the above listing, the JavaScript object obj has a reference to the DOM object represented by DivElement. The DOM object, in turn, has a reference to the JavaScript object through theexpandoProperty. A circular reference exists between the JavaScript object and the DOM object. Because DOM objects are managed through reference counting, neither object will ever be destroyed.

Another memory leak pattern

In Listing 2 a circular reference is created by calling the external function myFunction. Once again the circular reference between a JavaScript object and a DOM object will eventually lead to a memory leak.

Listing 2. A memory leak caused by calling an external function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html> <head> <script type="text/javascript"> document.write("Circular references between JavaScript and DOM!"); function myFunction(element) {     this.elementReference = element;     // This code forms a circular reference here     //by DOM-->JS-->DOM     element.expandoProperty = this; } function Leak() {     //This code will leak     new myFunction(document.getElementById("myDiv")); } </script> </head> <body onload="Leak()"> <div id="myDiv"></div> </body> </html>

As these two code samples show, circular references are easy to create. They also tend to crop up quite a bit in one of JavaScript's most convenient programming constructs: closures.

Closures in JavaScript

One of JavaScript's strengths is that it allows functions to be nested within other functions. A nested, or inner, function can inherit the arguments and variables of its outer function, and is private to that function. Listing 3 is an example of an inner function.

Listing 3. An inner function
1 2 3 4 5 6 7 8 9 function parentFunction(paramA) {         var a = paramA;         function childFunction()         {         return a + 2;         }         return childFunction(); }

JavaScript developers use inner functions to integrate small utility functions within other functions. As you can see in Listing 3, the inner function childFunction has access to the variables of the outerparentFunction. When an inner function gains and uses access to its outer function's variables it is known as a closure.

Learning about closures

Consider the code snippet shown in Listing 4.

Listing 4. A simple closure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <html> <body> <script type="text/javascript"> document.write("Closure Demo!!"); window.onload= function  closureDemoParentFunction(paramA) {     var a = paramA;     return function closureDemoInnerFunction (paramB)     {             alert( a +" "+ paramB);     }; }; var x = closureDemoParentFunction("outer x"); x("inner x"); </script> </body> </html>

In the above listing closureDemoInnerFunction is the inner function defined within the parent functionclosureDemoParentFunction. When a call is made to closureDemoParentFunction with a parameter of outer x, the outer function variable a is assigned the value outer x. The function returns with a pointer to the inner function closureDemoInnerFunction, which is contained in the variable x.

It is important to note that the local variable a of the outer function closureDemoParentFunction will exist even after the outer function has returned. This is different from programming languages such as C/C++, where local variables no longer exist once a function has returned. In JavaScript, the momentclosureDemoParentFunction is called, a scope object with property a is created. This property contains the value of paramA, also known as "outer x". Similarly, when the closureDemoParentFunction returns, it will return the inner function closureDemoInnerFunction, which is contained in the variable x.

Because the inner function holds a reference to the outer function's variables, the scope object with property a will not be garbage collected. When a call is made on x with a parameter value of inner x -- that is,x("inner x") -- an alert showing "outer x innerx" will pop up.

Listing 4 is a very simple illustration of a JavaScript closure. Closures are powerful because they enable inner functions to retain access to an outer function's variables even after the outer function has returned. Unfortunately, closures are excellent at hiding circular references between JavaScript objects and DOM objects.

Closures and circular references

In Listing 5 you see a closure in which a JavaScript object (obj) contains a reference to a DOM object (referenced by the id "element"). The DOM element, in turn, has a reference to the JavaScript obj. The resulting circular reference between the JavaScript object and the DOM object causes a memory leak.

Listing 5. Event handling memory leak pattern
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <html> <body> <script type="text/javascript"> document.write("Program to illustrate memory leak via closure"); window.onload=function outerFunction(){     var obj = document.getElementById("element");     obj.onclick=function innerFunction(){     alert("Hi! I will leak");     };     obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));     // This is used to make the leak significant }; </script> <button id="element">Click Me</button> </body> </html>

Avoiding memory leaks

The upside of memory leaks in JavaScript is that you can avoid them. When you have identified the patterns that can lead to circular references, as we've done in the previous sections, you can begin to work around them. We'll use the above event-handling memory leak pattern to demonstrate three ways to work around a known memory leak.

One solution to the memory leak in Listing 5 is to make the JavaScript object obj null, thus explicitly breaking the circular reference, as shown in Listing 6.

Listing 6. Break the circular reference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <html> <body> <script type="text/javascript"> document.write("Avoiding memory leak via closure by breaking the circular reference");     window.onload=function outerFunction(){     var obj = document.getElementById("element");     obj.onclick=function innerFunction()     {         alert("Hi! I have avoided the leak");         // Some logic here     };     obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));     obj = null; //This breaks the circular reference     }; </script> <button id="element">"Click Here"</button> </body> </html>

In Listing 7 you avoid the circular reference between the JavaScript object and the DOM object by adding another closure.

Listing 7. Add another closure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <html> <body> <script type="text/javascript"> document.write("Avoiding a memory leak by adding another closure"); window.onload=function outerFunction(){ var anotherObj = function innerFunction()          {             // Some logic here             alert("Hi! I have avoided the leak");          };      (function anotherInnerFunction(){         var obj =  document.getElementById("element");         obj.onclick=anotherObj })();         }; </script> <button id="element">"Click Here"</button> </body> </html>

In Listing 8 you avoid the closure itself by adding another function, thereby preventing the leak.

Listing 8. Avoid the closure altogether
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <html> <head> <script type="text/javascript"> document.write("Avoid leaks by avoiding closures!"); window.onload=function() {     var obj = document.getElementById("element");     obj.onclick = doesNotLeak; } function doesNotLeak() {     //Your Logic here     alert("Hi! I have avoided the leak"); }   </script> </head> <body> <button id="element">"Click Here"</button> </body> </html>

In conclusion

This article has explained how circular references can lead to memory leaks in JavaScript, particularly when combined with closures. You've seen several common memory leak patterns involving circular references and some easy ways to work around them. See Related topics to learn more about the topics discussed in this introductory article.

 

 

http://www.ibm.com/developerworks/web/library/wa-memleak/?S_TACT=105AGX52&S_CMP=cn-a-wa


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 知識點: 文件讀,寫操作,if 判斷, for 迴圈 salary = input("輸入你的工資:") bought_list = [] product_list = {} with open("product_list","r",encoding="utf-8") as f1: for item ...
  • Hibernate3 第二天 第一天回顧: 三個準備 創建資料庫 準備po和hbm文件 準備靈魂文件hibernate.cfg.xml 七個步驟 1 載入配置文件Configuration 2 創建會話工廠SessionFactory 3 獲取連接Session 4 開啟事務Transaction ... ...
  • 上篇我們學會瞭如何使用及定義變數。按照尿性,一般接下來就該學基本數據類型的運算了。 沒錯,本篇就仍是這麼俗套的來講講這無聊但又必學的基本數據類型的運算了。 基本數據類型運算 操作符 符號 | 語義 | 描述 | | + | 加 | 10+10,結果為20 | 減 | 10 3, 結果為7 | 乘 | ...
  • 一、python介紹 Python 的創始人為Guido van Rossum。Guido為了打發聖誕節的無趣,於1989年發明,在荷蘭國家數學和電腦科學研究所設計出來的(作為ABC 語言的一種繼承),之所以起名Python,是因他是Monty Python的喜劇團體的愛好者。Python第一個公 ...
  • php 中header 函數 我可能見多了,只要用來跳轉。今天在閱讀TP源碼的時候發現,header函數有第三個參數。有些困惑所以找到手冊查閱下,發現 瞬間就明白了第三個參數是用來指定,返回狀態碼的。 還有看到parse_str 函數 第二個參數傳遞了一個數組。有些困惑一查手冊發現 手冊說的很明白, ...
  • 頁面直接請求, Controller代碼 ...
  • 一.開發工具規範: 1. 開發工具經項目負責人調試後統一確定。 2. 開發工具一經確定不允許集成任何非統一插件,若有需要,經項目負責人同意後統一為 項目組成員添加。 3. 開發工具的編碼格式不允許修改。 二.排版規範: 1. 關鍵詞(或變數)和操作符之間加一個空格。 例如:int iCont = 1 ...
  • 集合技術 作業 作業 猜數字游戲 猜數字游戲 /* * 猜數字游戲 */ public class HomeWork1 { public static void main(String[] args) { // 獲取被猜的那個數字,需要使用隨機數類產生 Random r = new Random() ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...