[Javascript] memory leaks and circular reference parsing

Source: Internet
Author: User
Tags setinterval

Memory leaks

In JavaScript, we seldom pay attention to memory management. We create variables, use variables, and browsers look at these underlying details as normal.

But when the application becomes more complex and Ajax, or the user stays on a page for too long, we may need to pay attention to some problems, such as a browser that spends more than 1G of memory, and is constantly increasing. These problems are often caused by memory leaks.

Javascript memory leaks

The core concept of this JavaScript memory management is the concept of non-accessibility.

A set of 11 distinct objects will be considered to be accessible: these objects are known like roots.

These include all of the objects in the stack where they are referenced (including, all local variables, parameters in the method being called), and any global variables.

2 objects are saved in memory and they are reachable from the Roots object by a reference chain that references the shippers.


Here is a GC garbage collector in the browser, used to clear the unused objects in memory.


Garbage Collection Example

Function menu (title) {  this.title = title  This.elem = document.getElementById (' id ')}var menu = new Menu (' My Menu ') ) Document.body.innerHTML = "  //(1) menu = new Menu (' his menu ')//(2)


Consider the memory structure:



In step (1), the body.innerhtml is cleared, so its child nodes are also deleted because they are no longer associated.

But this element #id is an exception, he is associated with Menu.elem, so the object will always exist in memory, of course, if you check his parentnode, you will get a null value.


Note: Individual DOM elements can be saved in memory even if their parent is removed.

In step (2), the reference window.menu is defined so that the previous menu will automatically be removed via the browser's GC because it is no longer associated.



Circular Reference Collection

Closures often result in circular references, such as:

function SetHandler () {  var elem = document.getElementById (' id ')  elem.onclick = function () {    //...  }}

Here, this DOM element directly references the anonymous function via the onclick. And this function references the Elem element through the external lexical environment.


(Here's a little more, about [[scope]] is the internal property of function, when creating functions, the lexical environment of the external function is added to [[scope]], where the scope of JavaScript is concerned. )

Such a memory structure will appear even if there is no code inside the handler function. Some special methods, such as Addeventlistener/attachevent, also create a reference internally.


In this handler function is usually cleared when the Elem dies.

function CleanUp () {  var elem = document.getElementById (' id ')  elem.parentNode.removeChild (Elem)}

Call Clearup to delete the element from the DOM. There is still a reference, Lexialenvironment.elem, but there is no nested functions, so lexialenvironment can be recycled.

After this, elem becomes unrelated and is recycled along with his handlers.


Memory leaks

Memory leaks mainly occur when some browsers are not able to remove unused objects from memory because of some problems.

This can happen for a number of reasons, such as browser bugs, browser extension issues, more or less, our own code errors.


Dom-js memory leaks under IE 8

The browser before IE8 cannot clean up circular references between the DOM and JavaScript. This problem is relatively more severe in IE6 versions prior to Windows XP SP3

Because the memory cannot be released before the page is unloaded.


So SetHandler leaked in the browser before IE 8, elem and these closures can not be cleared.

function SetHandler () {  var elem = document.getElementById (' id ')  elem.onclick = function () {/* ... */}}


This behavior exists not only for DOM elements, including XMLHttpRequest or other COM objects.

The method used to break the circular reference under IE:




We define Elem = null, so this handler is no longer associated with the DOM element, and this loop naturally breaks.


XMLHttpRequest Memory Management and Disclosure

The following code is leaked in I9 browser memory:

var xhr = new XMLHttpRequest ()//or ActiveX in older Iexhr.open (' GET ', '/server.url ', true) Xhr.onreadystatechange = Funct Ion () {  if (xhr.readystate = = 4 && Xhr.status = =) {                //...  }} Xhr.send (NULL)

Look at the memory structure:



This asynchronous XMLHttpRequest object has been tracked by the browser because there is an internal reference associated with it.

When the request is finished, the reference is deleted, so the XHR becomes a non-associative object. However, the following browsers do not do this IE9.

Fortunately, to fix this bug is very simple, we need to remove this xhr from the closure and use it with this in this handler function. As follows:

var xhr = new XMLHttpRequest ()  xhr.open (' GET ', ' jquery.js ', true)  Xhr.onreadystatechange = function () {  if ( This.readystate = = 4 && This.status = =) {                document.getElementById (' Test '). innerhtml++  }}   Xhr.send (null) XHR = null}, 50)


This will not have a circular reference.


Setinterval/settimeout

An internal reference is also available when using settimeout/setinterval and is traced to the end, then clear up.


For setinterval This end occurs in Clearinterval, this may lead to memory leaks when this method actually does nothing, but the interval is not cleared.


The size of the memory leak

The size of the memory-leaking data structure may be small.

But this closure causes all variables of the external function to be left behind, when the intrinsic function is active.

So, as you can imagine, you create a function, and one of the variables contains a large string.

function f () {  var data = "Large piece of data, probably received from server"/  * do something using data */  F Unction inner () {    //...  }  Return inner}

While the function inner function stays in memory and then the lexicalenvironment with a large variable inside would hang in M Emory until the inner function is alive.

In fact, this may not leak, many of the fucntions may be created because of some reasonable reasons. For example, for each request, it is not clear, because they are some processing functions or something else.


If this data is used only in an external function, we can invalidate it in an external method.

function f () {  var data = "Large piece of data, probably received from server"/  * do something using data */  F Unction inner () {    //...  } data = null  return inner}


Right now. This data remains in memory as a property of a lexical environment, but it no longer needs to occupy too much space.


JQuery memory leaks and avoidance methods

JQuery uses $.data to avoid IE 6 7 memory leaks. Unfortunately, it led to some new JQuery special memory leaks.

This core principle about $.data is that any JavaScript entity is restricted to reading an element using the following way

Works on this site cause it's using jquery$ (document.body). Data (' prop ', ' Val ')//Setalert ($ (document.body). Data (' Prop '))//Get

JQuery $ (elem). Data (Prop,val) follow these steps:

The 1 element gets a unique token if it does not exist:

elem[Jquery.expando] = id = ++jquery.uuid  //from JQuery source

2 data is set to a special object Jquery.cache:

jquery.cache[id][' prop '] = val

When this date is read from an element:

1 The unique identifier of this element will be returned: id = Elem[jquery.expando]

2 This data will be read from Jquery.cache[id]


jquery sets up this API to make DOM elements no longer directly referencing JavaScript elements. It uses a quantity, but it's safe.

This data is stored in the Jquery.cache. The internal event handler function also uses the $.data API.

It also creates an effect on the other hand, and an element cannot be removed from the DOM using local calls.


The following code causes a memory leak in all browsers:

$ (' <div/> ')  . HTML (New Array (). Join (' text '))//div with a text, maybe ajax-loaded  . Click (function () { })  . AppendTo (' #data ') document.getElementById (' data '). InnerHTML = "

This leak occurred because Elem was removeed by clearing the parent's innerhtml. But this data is still stored in the Jquery.cache.

More importantly, this event handler function references Elem, so this event handler and Elem remain in memory and the entire closure.


A simple leak example

function Go () {  $ (' <div/> ')    . HTML (New Array (). Join (' text '))     . Click (function () {})}

The problem with this example is that this element was created, but not used. So after this function is defined, the reference disappears, but the Jquery.cache still exists.


----------------------------------------------------------------------------

Original address: Http://javascript.info/tutorial/memory-leaks

[Javascript] memory leaks and circular reference resolution

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.