JavaScript also talk about memory optimization _javascript tips

Source: Internet
Author: User
Tags closure event listener garbage collection memory usage tmlp

In contrast to C + +, the use of JavaScript in memory has made us more focused on the writing of business logic in development. However, with the continuous complexity of the business, single page applications, mobile HTML5 applications and node.js programs and so on, JavaScript memory problems caused by the cotton, memory overflow phenomenon has become no longer unfamiliar.

This article will explore the use and optimization of memory from the language level of JavaScript. From the familiar or slightly heard aspects, to most of the time we will not notice places, we are one by one to analyze.

1. Language-level memory management

1.1 Scopes

Scope (scope) is a very important operating mechanism in JavaScript programming, it does not fully arouse the attention of beginners in synchronous JavaScript programming, but in asynchronous programming, good scope control skill becomes the essential skill of JavaScript developer. In addition, scopes play a crucial role in JavaScript memory management.

In JavaScript, a functional invocation, with statement, and global scope that can form a scope.

As an example of the following code:

Copy Code code as follows:

var foo = function () {
var local = {};
};
Foo ();
Console.log (local); => undefined

var bar = function () {
local = {};
};
Bar ();
Console.log (local); => {}

Here we define the Foo () function and the bar () function, and their intent is to define a variable named Local. But the end result is quite different.

In the Foo () function, we use the VAR statement to declare that a local variable is defined, and because a scope is formed within the function body, the variable is defined into the scope. and the Foo () function body does not do any scope extension processing, so the local variable is destroyed after the function has finished executing. The variable cannot be accessed in the outer-layer scope.

In the bar () function, the local variable is not declared with the Var statement, and instead is defined directly as a global variable. So the outer scope can access this variable.

Copy Code code as follows:

local = {};
The definition here is equivalent to
global.local = {};


1.2 Scope chain

In JavaScript programming, you are bound to encounter multiple layers of nested functions, which is the representation of a typical scope chain.

As shown in the following code:

Copy Code code as follows:

function foo () {
var val = ' Hello ';

function Bar () {
function Baz () {
Global.val = ' world; '
}
Baz ();
Console.log (Val); => Hello
}
Bar ();
}
Foo ();

Based on the previous elaboration of the scope, you may think that the code here shows the result is world, but the actual result is hello. Many beginners will start to feel confused here, so let's take a look at how this piece of code works.

Because of JavaScript, the lookup of a variable identifier is found outward from the current scope until the global scope. So access to variables in JavaScript code can only be done outward, not in reverse.



The execution of the Baz () function defines a global variable, Val, in the global scope. In the bar () function, when you access the identifier for Val, follow the from inside to outside of the SID Lookup principle: In the scope of the bar function is not found, then go to the previous layer, that is, the scope of the Foo () function to find.

However, the key to all this confusion is here: This identifier accesses the variable that matches in the scope of the Foo () function and does not continue to look out, so the global variable Val defined in the Baz () function does not have an effect on this variable access.

1.3 Closures

We know that the identifier lookup in JavaScript follows the principle from inside to outside. However, with the complexity of business logic, the single delivery order is far from satisfying the increasing demand.

Let's take a look at the following code:

Copy Code code as follows:

function foo () {
var local = ' Hello ';
return function () {
return to local;
};
}
var bar = foo ();
Console.log (Bar ()); => Hello

The technique shown here for the outer scope to access the inner scope is the closure (Closure). Thanks to the application of higher order functions, the scope of the Foo () function is "extended".

The Foo () function returns an anonymous function that exists within the scope of the Foo () function, so you can access the local variables within the scope of the Foo () function and save their references. Because this function returns the local variables directly, the bar () function can be executed directly in the outer scope to get the locals.

Closures are an advanced feature of JavaScript that we can use to achieve more complex effects to meet different needs. However, it is important to note that because the function with the internal variable reference is taken outside the function, the variable within the scope is not necessarily destroyed after the function has been executed until the reference to the internal variable is completely lifted. So the closure application is very easy to cause memory can not be released.

2. JavaScript Memory recovery mechanism

Here I will use the chrome and Node.js, the Google launched by the V8 engine as an example, a brief description of JavaScript memory recycling mechanism, more detailed content can buy my good friend Pauling book "Node.js" to learn, where "memory control" A very detailed introduction in the chapter.

In V8, all JavaScript objects are allocated in memory by "heap".



When we declare a variable and assign a value in code, V8 allocates a portion of the heap memory to the variable. If the requested memory is not sufficient to store the variable, V8 continues to request memory until the heap reaches the V8 memory limit. By default, the maximum size of V8 heap memory is 1464MB in 64-bit systems, 732MB in 32-bit systems, or approximately 1.4GB and 0.7GB.

In addition, V8 manages the JavaScript objects in heap memory: The new generation and the new generation. The new generation is a short life cycle of JavaScript objects, such as temporary variables, strings and so on, while the older generation for many times after the garbage collection is still alive, long survival period of objects, such as the main controller, server objects.

Garbage collection algorithm has always been an important part of programming language research and development, and the garbage collection algorithm used in V8 mainly has the following kinds:

1.Scavange algorithm: The memory space is managed by the way of copying, which is mainly used in the new generation memory space;
2.mark-sweep algorithm and mark-compact algorithm: through the tag to the heap memory collation and recovery, mainly used in the generation of objects to check and recycle.


PS: A more detailed V8 garbage collection implementation can be learned by reading related books, documents, and source code.

Let's take a look at what the JavaScript engine is doing to recycle objects.

2.1 Scopes and references

Beginners often mistakenly assume that when the function completes, the object declared inside the function is destroyed. But in practice this understanding is not rigorous and comprehensive, it can easily lead to confusion.

Reference (Reference) is a very important mechanism in JavaScript programming, but it is strange that the average developer will not pay attention to it or even understand it. A reference refers to the abstract relationship of "code access to an object", which is somewhat similar to a C + + pointer, but not the same thing. References are also one of the most critical mechanisms for JavaScript engines in garbage collection.

Take the following code as an example:

Copy Code code as follows:

// ......
var val = ' Hello World ';
function foo () {
return function () {
return Val;
};
}
Global.bar = foo ();
// ......

After reading this piece of code, can you say which objects are still alive after the execution of this part of the code?

According to the principles, the objects in this code that are not recycled are Val and bar (), what is the reason for them not to be recycled?

How does a JavaScript engine do garbage collection? The garbage collection algorithm mentioned earlier is only used when it comes to recycling, so how does it know which objects can be recycled and which objects need to survive? The answer is a reference to a JavaScript object.

In JavaScript code, even if simply writing down a variable name as a single line without doing anything, the JavaScript engine will assume that this is an access behavior to the object, and that there is a reference to the object. In order to ensure that the behavior of garbage collection does not affect the operation of program logic, the JavaScript engine will never be able to recycle the objects that are being used, otherwise it will be messed up. So the criterion for determining whether an object is in use is whether a reference to that object still exists. But in fact, this is a compromise, because JavaScript references are transferable, and it is possible that some references are brought to the global scope, but in fact there is no need to access them in the business logic and should be recycled, but JavaScript The engine will still be rigid in thinking that the program still needs it.

How to use variables and references in the right posture is the key to optimizing JavaScript from the language level.

3. Optimize your JavaScript

Finally came to the point, thank you for your patience to see here, after so many introductions, I believe you have the JavaScript memory management mechanism has a good understanding, then the following skills will make you more powerful.

3.1 Use of functions

If you have the habit of reading excellent JavaScript programs, you will find that many of Daniel's development of the front-end JavaScript code often uses an anonymous function to wrap around the outermost layer of the code.

Copy Code code as follows:

(function () {
Main business code
})();

Some are even more advanced:
Copy Code code as follows:

;(function (Win, Doc, $, undefined) {
Main business code
}) (window, document, JQuery);

Even the front-end modular loading solutions such as Requirejs, Seajs, Ozjs, are in a similar form:
Copy Code code as follows:

Requirejs
define ([' jquery '], function ($) {
Main business code
});

Seajs
Define (' M odule ', [' dep ', ' underscore '], function ($, _) {
Main business code
});

If you say that a lot of Node.js Open source project code does not deal with this, then you are wrong. Node.js will wrap each. js file into the following form before actually running the code:
Copy Code code as follows:

(function (exports, require, module, __dirname, __filename) {
Main business code
});

What's the benefit of doing that? We all know that the beginning of the article said that JavaScript can form the scope of the function of the call, with statements and global scope. And we know that the objects that are defined in the global scope are likely to survive until the process exits, and if it's a large object, that's a problem. For example, some people like to do template rendering in javascript:

Copy Code code as follows:

<?php
$DB = mysqli_connect (server, user, password, ' MyApp ');
$topics = Mysqli_query ($db, "select * from topics;");
?>
<!doctype html>
<meta charset= "UTF-8" >
<title> are you the monkey's tease, please? </title>
<body>
<ul id= "Topics" ></ul>
<script type= "Text/tmpl" id= "Topic-tmpl" >
<li>
<p><%=content%></p>
</li>
</script>
<script type= "Text/javascript" >
var data = <?php echo json_encode ($topics);?>;
var Topictmpl = document.queryselector (' #topic-tmpl '). InnerHTML;
var render = function (TMLP, view) {
var complied = TMLP
. replace (/\n/g, ' \\n ')
. replace (/<%= ([\s\s]+?) %>/g, function (match, code) {
Return ' + Escape (' + code + ') + ';
});

complied = [
' var res = '; ',
' With (view | | {}) {',
' res = ' + complied + '; ',
'}',
' Return res; '
].join (' \ n ');

var fn = new Function (' View ', complied);
RETURN fn (view);
};

var topics = Document.queryselector (' #topics ');
function init ()
Data.foreach (function (topic) {
Topics.innerhtml + = render (Topictmpl, topic);
});
}
Init ();
</script>
</body>

This kind of code in the Novice's work often can see, what is the problem here? If the amount of data obtained from the database is very large, the front end completes the template rendering, and the data variable is left on the sidelines. Because the variable is defined in the global scope, the JavaScript engine does not recycle it. So the variable will always exist in the Day memory until the page is closed.

But if we make some very simple changes, wrapping a layer of functions outside of the logical code, the effect is quite different. When the UI render is complete, the code's reference to data is lifted, and when the outermost function completes, the JavaScript engine begins to examine the object, and data can then be recycled.

3.2 Absolutely do not define global variables

As we have just mentioned, when a variable is defined in the global scope, the JavaScript engine does not reclaim it by default. So the variable will always exist in the Day memory until the page is closed.

Then we have always followed a principle: never use global variables. Although global variables are really easy to develop in development, the problems caused by global variables are far more serious than the convenience they bring.

Make the variable not easy to be recycled;
1. It is easy to confuse multiple people in collaboration;
2. It is easy to be disturbed in the scope chain.
3. With the above packaging function, we can also use the wrapper function to deal with "global variables."

3.3 Manually unbind variable references

If a variable is no longer needed in the business code, then the variable reference can be manually lifted so that it is recycled.

Copy Code code as follows:

var data = {/* Some big data */};
blah blah blah
data = null;

3.4 Use of callback

In addition to using closures for internal variable access, we can also use the current very popular callback function for business processing.

Copy Code code as follows:

function GetData (callback) {
var data = ' Some big data ';

Callback (null, data);
}

GetData (function (err, data) {
Console.log (data);

A callback function is a technique for subsequent delivery styles (continuation passing style, CPS), a style of programming that shifts the business focus of a function from the return value to a callback function. And there are a lot of benefits compared to closures:

1. If the incoming parameter is the underlying type (such as a string, numeric value), the parameters passed in the callback function are copied, and the business code is more easily recycled after it is used;
2. Through the callback, we can complete the synchronization request, but also can be used in asynchronous programming, which is now very popular in a writing style;
3. The callback function itself is usually a temporary anonymous function, and once the request function has been executed, the reference to the callback function itself is lifted and itself reclaimed.

3.5 Good closure Management

When we need to use closures for our business needs (such as cyclic event bindings, private properties, parameter callbacks, and so on), be cautious about the details.

Cyclic binding events are a required course for JavaScript closures, and we assume a scenario where there are six buttons, corresponding to six events, and when the user clicks the button, the corresponding event is output in the specified place.


Copy Code code as follows:

var btns = Document.queryselectorall ('. btn '); 6 elements
var output = document.queryselector (' #output ');
var events = [1, 2, 3, 4, 5, 6];

Case 1
for (var i = 0; i < btns.length; i++) {
Btns[i].onclick = function (evt) {
Output.innertext + = ' clicked ' + events[i];
};
}

Case 2
for (var i = 0; i < btns.length; i++) {
Btns[i].onclick = (function (index) {
return function (evt) {
Output.innertext + = ' clicked ' + Events[index];
};
}) (i);
}

Case 3
for (var i = 0; i < btns.length; i++) {
Btns[i].onclick = (function (event) {
return function (evt) {
Output.innertext + = ' clicked ' + event;
};
}) (Events[i]);
}

The first solution here is obviously a typical cyclic binding event error, which is not detailed here and can be used to refer to my answer to a netizen; the difference between the second and third scenarios is the parameters that are passed in the closure.

The second scenario passes in a parameter that is the current loop subscript, and the latter is passed directly to the appropriate event object. In fact, the latter is more suitable for a large number of data applications, because in functional programming of JavaScript, the arguments passed in function calls are basic type objects, the form participants in the function body are a copy of the value, which is defined as a local variable within the scope of the function body, After the event binding is complete, you can manually dereference the events variable to mitigate the memory footprint in the outer scope. And when an element is deleted, the corresponding event listener, event object, and closure function are also destroyed and recycled.

3.6 Memory is not cached

Caching plays an important role in business development and can reduce the burden of time and space resources. Note, however, that memory is not easily used as a cache. Memory for any program development is an inch of gold things, if not very important resources, please do not put directly in memory, or set an expiration mechanism, automatic destruction of expired cache.

4. Check JavaScript for memory usage

In peacetime development, we can also use a number of tools to the JavaScript memory usage analysis and troubleshooting.

4.1 Blink/webkit Browser

In the Blink/webkit browser (Chrome, Safari, Opera etc), we can use the Developer Tools Profiles tool to check our program memory.


Memory Check in 4.2 node.js

In Node.js, we can use the Node-heapdump and Node-memwatch modules for memory checking.

Copy Code code as follows:

var heapdump = require (' Heapdump ');
var fs = require (' FS ');
var path = require (' path ');
Fs.writefilesync (Path.join (__dirname, ' app.pid '), process.pid);
// ...

Copy Code code as follows:
<span style= "Font-family:georgia, ' Times New Roman ', ' bitstream Charter ', times, serif; font-size:14px; line-height:1.5em; " > After introducing node-heapdump into the business code, we need to send a SIGUSR2 signal to the node.js process at some runtime, allowing Node-heapdump to capture a snapshot of the heap memory. </span>

Copy Code code as follows:
$ KILL-USR2 (cat app.pid)

This will have a snapshot file named in heapdump-<sec>.<usec>.heapsnapshot format in the file directory, which we can open using the Profiles tool in the browser's developer tools. and check it out.

5. Summary

Soon came the end of the article, this share mainly to show you the following points:

1.JavaScript on the language level, with the memory use of things closely related;
2.JavaScript memory management, recovery mechanism;
3. How to use memory more efficiently, so that the production of JavaScript can be more expanded vitality;
4. How to check the memory when you encounter a memory problem.

Hope that through the study of this article, you can produce more excellent JavaScript code, so that the mother at ease, let the boss rest assured.

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.