JavaScript memory optimization

Source: Internet
Author: User
Tags closure event listener wrapper tmlp

In contrast to C + +, the use of JavaScript in memory has allowed us to focus more on the writing of business logic in development. But as business continues to complicate the development of single-page applications, mobile HTML5 applications, and node. JS programs, memory problems in JavaScript are no longer familiar.

1. Language-level memory management 1.1 scopes

Scope (scope) is a very important operating mechanism in JavaScript programming, which does not fully arouse the attention of beginners in the programming of synchronous JavaScript, but in asynchronous programming, good scope control skills become a necessary skill for JavaScript developers. In addition, scopes play a critical role in JavaScript memory management.

In JavaScript, there are function calls, with statements, and global scopes that can form a scope. As an example of the following code:

var foo = function() {  var local = {};};foo();console.log(local); //=> undefinedvar bar = function() {  local = {};};bar();console.log(local); //=> {}

Here we define foo() functions and bar() functions, all of which are intended to define a local variable named. But the end result was quite different.

In a foo() function, we use var a statement to declare a local variable, and because a scope is formed inside the function body, the variable is defined in that scope. and the foo() function body does not do any scope extension processing, so after the function is finished, this local variable is also destroyed. The variable cannot be accessed in the outer scope.

Within the bar() function, the local variable is not declared with a var statement, but instead is local defined as a global variable. Therefore, the outer scope can be accessed to this variable.

local = {};// 这里的定义等效于global.local = {};
1.2 Scope chain

In JavaScript programming, you are bound to encounter multiple layers of function nesting scenarios, which is the typical representation of the scope chain. As shown in the following code:

function foo() {  var val = ‘hello‘;  function bar() {    function baz() {      global.val = ‘world;‘    }    baz();    console.log(val); //=> hello  }  bar();}foo();

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

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

baz()Execution of a function defines a global variable in the global scope val . In the bar() function, val when access to this identifier, according to the principle from the inside out of the German lookup: In the scope of the bar function is not found, then to the previous layer, that is, foo() the scope of the function to find.

However, the key to making people confused is here: This identifier access foo() does not continue to look for the matching variable in the scope of the function, so the baz() global variable defined in the function val does not have an impact on this variable access.

1.3 Closures

We know that identifier lookups in JavaScript follow the principles from the inside out. But with the complexity of business logic, the single delivery order is far from meeting the increasing demand.

Let's take a look at the following code:

function foo() {  var local = ‘Hello‘;  return function() {    return local;  };}var bar = foo();console.log(bar()); //=> Hello

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

foo()The function returns an anonymous function that exists within the scope foo() of the function, so you can access the foo() variable within the scope of the function local and save its reference. Because this function returns the variable directly local , the function can be executed directly in the outer scope bar() to obtain the local variable.

Closures are a high-level feature of JavaScript, and we can use it to achieve more complex effects to meet different needs. But it is important to note that the The function referenced by the internal variable takes out the outside of the function, so the variable within the scope is not necessarily destroyed after the function is executed, until the reference to the internal variable is completely dismissed. Therefore, the application of closures can easily cause memory to be unable to release the situation.

2. JavaScript's memory recovery mechanism

Here I will take the example of Chrome and node. js used by Google to introduce the V8 engine, a brief introduction of JavaScript memory recycling mechanism, more detailed content can buy my good friend Pauling's book, "Simple node. js" To learn, where "memory control" A very detailed introduction in the chapter.

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

When we declare a variable in code and assign a value, V8 allocates a portion of it to the variable in the heap memory. 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 heap memory size of V8 is 1464MB in 64-bit systems and 732MB in 32-bit systems, which is about 1.4GB and 0.7GB.

In addition, V8 manages the generation of JavaScript objects in heap memory: Cenozoic and Laosheng. The new generation is a short-lived JavaScript object, such as temporary variables, strings, and so on, whereas the Laosheng generation is a long-lived object, such as host controller, server object, and so on, which has survived multiple garbage collection.

is the garbage collection algorithm always important in the development of programming languages? , and the garbage collection algorithm used in V8 has the following main types:

    1. Scavange algorithm: Memory space management by means of replication, mainly used in the new generation of memory space;
    2. Mark-sweep algorithm and mark-compact algorithm: The heap memory is organized and recycled by tags, which is mainly used for checking and recycling of Laosheng objects.

PS: More detailed V8 garbage collection implementations can be learned by reading related books, documents, and source code.

Let's look at the circumstances under which the JavaScript engine will recycle which objects.

2.1 Scopes and references

Beginners often assume that when a function is finished, the objects declared inside the function are destroyed. But in fact this understanding is not rigorous and comprehensive, it is easy to cause confusion.

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

An example of the following code:

// ......var val = ‘hello world‘;function foo() {  return function() {    return val;  };}global.bar = foo();// ......

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

According to the relevant principles, there are no objects in this code that have been released val and bar() What are the reasons why they cannot be recycled?

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

In JavaScript code, even if you simply write down a variable name as a single row without doing anything, the JavaScript engine will assume that this is an access behavior for the object, and there is a reference to the object. To ensure that the behavior of garbage collection does not affect the operation of the program logic, the JavaScript engine must not be able to recycle the objects being used, or it will be out of order. So judging whether the object is in use is the standard, whether there is still a reference to the object. But in fact, this is a compromise, because JavaScript references can be transferred, it is possible that some references are brought to the global scope, but in fact, in the business logic has no need to access it, should be recycled, but JavaScript The engine will still be inflexible to think that the program still needs it.

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

3. Optimize your JavaScript

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

3.1 Use of functions

If you have the habit of reading a good JavaScript project, you will find that many of them often use an anonymous function to package the outermost layer of code when developing the front-end JavaScript code.

;(function() {  // 主业务代码})();

Some are even more advanced:

;(function(win, doc, $, undefined) {  // 主业务代码})(window, document, jQuery);

Even the front-end modular loading solutions, such as Requirejs, SEAJS, OZJS, etc., are in a similar form:

// RequireJSdefine([‘jquery‘], function($) {  // 主业务代码});// SeaJSdefine(‘m??odule‘, [‘dep‘, ‘underscore‘], function($, _) {  // 主业务代码});

If you say that many of the code for the node. JS Open Source project doesn't work like this, you're wrong. node. JS will wrap each of the. js files into the following form before actually running the code:

(function(exports, require, module, __dirname, __filename) {  // 主业务代码});

What is the benefit of doing this? We all know that at the beginning of the article, there are function calls, with statements, and global scopes that can form scopes in JavaScript. And we also know that the object that is defined in the global scope is likely to survive until the process exits, and if it is a large object, it will be troublesome. For example, some people like to make template rendering in javascript:

<?php $db = mysqli_connect (server, user, password, ' MyApp '); $topics = Mysqli_query ($db, "select * from topics;");? ><!doctype html>

This kind of code in the Novice's work often can see, what is the problem there? If the amount of data fetched from the database is very large, the variables are left idle after the front-end template rendering is complete data . Because this variable is defined in the global scope, the JavaScript engine does not recycle it. So the variable will always exist in Laosheng Day memory until the page is closed.

But if we make some very simple changes and wrap a layer of functions outside of the logic code, the effect is quite different. When the UI rendering is complete, the reference to the code pair is data dismissed, and when the outermost function finishes, the JavaScript engine begins to examine the objects in it and data can then be recycled.

3.2 Never define global variables

As we've just talked about, 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 Laosheng Day memory until the page is closed.

So we've been following 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.

    1. Make the variable not easy to be recycled;
    2. Confusing when collaborating with many people;
    3. is susceptible to interference in the scope chain.

With the wrapper function above, we can also handle "global variables" through the wrapper function.

3.3 Manual release of variable references

If a variable is no longer needed in the business code, you can manually de-reference the variable so that it is recycled.

var data = { /* some big data */ };// blah blah blahdata = null;
3.4 Use of callbacks

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

function getData(callback) {  var data = ‘some big data‘;  callback(null, data);}getData(function(err, data) {  console.log(data);});

The callback function is a technique of subsequent passing styles (continuation passing style, CPS), a style of programming that shifts the business focus of the function from the return value to the callback function. And it has many advantages over closures:

    1. If the parameter passed in is the underlying type (such as a string, numeric value), the parameters passed in the callback function will be copied, and after the business code is used, it is more likely to be recycled;
    2. With callbacks, we can also use asynchronous programming in addition to the synchronous request, which is now a very popular writing style;
    3. The callback function itself is usually also a temporary anonymous function, once the request function is completed, the callback function itself is dismissed, and itself is recycled.
3.5 Good closure Management

When our business needs (such as loop event bindings, private attributes, including parameter callbacks, etc.) must be closed, be careful with the details.

Cyclic binding events are required for JavaScript closures, and we assume a scenario where there are six buttons that correspond to six events, and when the user taps the button, the corresponding event is output at the specified location.

var btns = document.querySelectorAll(‘.btn‘); // 6 elementsvar output = document.querySelector(‘#output‘);var events = [1, 2, 3, 4, 5, 6];// Case 1for (var i = 0; i < btns.length; i++) {  btns[i].onclick = function(evt) {    output.innerText += ‘Clicked ‘ + events[i];  };}// Case 2for (var i = 0; i < btns.length; i++) {  btns[i].onclick = (function(index) {    return function(evt) {      output.innerText += ‘Clicked ‘ + events[index];    };  })(i);}// Case 3for (var i = 0; i < btns.length; i++) {  btns[i].onclick = (function(event) {    return function(evt) {      output.innerText += ‘Clicked ‘ + event;    };  })(events[i]);}

Here the first solution is obviously a typical loop-bound event error, which is not detailed here, in detail can be referred to a netizen's answer, and the second and third scenario is the difference between the closure of the parameters.

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

3.6 Memory is not a cache

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

4. Check the memory usage of JavaScript

In the usual development, we can also use some tools to analyze and troubleshoot memory usage in JavaScript.

4.1 Blink/webkit Browser

In Blink/webkit browser (Chrome, Safari, Opera etc), we can use the Profiles tool of developer tools to check our programs in memory.

4.2 Memory Check in node. js

In node. js, we can use the Node-heapdump and Node-memwatch modules to enter?? Row memory check.

var heapdump = require(‘heapdump‘);var fs = require(‘fs‘);var path = require(‘path‘);fs.writeFileSync(path.join(__dirname, ‘app.pid‘), process.pid);// ...

After introducing node-heapdump into the business code, we need to send a SIGUSR2 signal to the node. JS process at some point in time, allowing Node-heapdump to snap a snapshot of the heap memory.

$ kill -USR2 (cat app.pid)

So there will be a heapdump-<sec>.<usec>.heapsnapshot format-named Snapshot file under the file directory, and we can use the Profiles tool in the browser's developer tools to open it and check it.

5. Summary

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

    1. JavaScript at the language level, and memory use is closely related to things;
    2. Memory management and recovery mechanism in JavaScript;
    3. How to use memory more efficiently, so that the production of JavaScript can be more expanded vitality;
    4. How to perform a memory check when encountering memory problems.

JavaScript memory optimization

Related Article

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.