[Javascript] memory leaks and circular reference parsing

Source: Internet
Author: User
Tags closure

Memory leaks

In JavaScript, we have very little attention to memory management.

We create variables, use variables, and browsers look at these underlying details as normal.

But when applications become more complex and Ajax-or users stay on a page for too long-we may need to pay attention to some issues. such as a browser to spend more than 1G of memory, and is constantly added.

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.

11 distinct sets of objects will be thought to be accessible: these objects are known like roots.

Contains all of the objects that are referenced in the stack (including, all local variables). The number of arguments in the method being called), and the global variable regardless of what.

2 objects are saved in memory and they are able to reach from the Roots object through a reference chain that references the shippers.


Here is a GC garbage collector in the browser. Used to clear objects that are not practical 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 connected by Menu.elem, so the object will always exist in memory, of course. Assuming 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 the previous menu is no longer associated. It will voluntarily be removed via the browser's GC.



Circular Reference Collection

Closures often lead to 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.


(Say a little more about [[Scope]] is the internal property of the function. When you create a function. Adds the lexical environment of the external function to [[Scope]], where the scope of the JavaScript is involved. )

This kind of memory structure will appear even if there is no code inside this handler function, no matter what. Some special methods, such as Addeventlistener/attachevent, also create a reference internally.


Cleanup is usually done in this handler function. When the Elem died.

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 that. Elem becomes unrelated and is recycled with his handlers.


Memory leaks

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

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 before IE6 Windows XP SP3 version number

The memory cannot be freed 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 () {/* ... */}}


Not only DOM elements. Contains XMLHttpRequest or other COM objects. This behavior can occur.

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 leaking from the following browser memory in I9:

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 to it.

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

Fortunately, it's easy to fix this bug. We need to remove this xhr from this closure and use it with this in this handler function.

For example, the following:

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

There is also an internal reference to the use of settimeout/setinterval and is traced to the end. Then clear up.


For setinterval This end occurs in Clearinterval, this can 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 the 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 includes 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. A lot of fucntions may be created due to some reasonable reasons. For example, for each request, it is not clear. Because they are some processing function or something else.


Suppose this data is used only in external functions. 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}


Now.

This data remains in memory as a property of a lexical environment. It's just that 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's not. It led to some new JQuery special memory leaks.

This core principle about $.data is that no matter what the JavaScript entity is restricted to read an element using a method such as the following

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) follows, for example, the following steps:

The 1 element gets a unique token assuming 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 very safe.

This data is stored in the Jquery.cache.

The internal event handler functions the same as using the $.data API.

At the same time, there is also the effect that an element cannot be removed from the DOM using a local call.


For example, the following code causes memory leaks 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 occurs 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 sample of leaks

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

The problem with this example is that this element has been created. But not used.

So after this function is defined, the reference disappears. But this jquery.cache is still there.


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

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

[Javascript] memory leaks and circular reference parsing

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.