In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article focuses on "what are the ways to avoid JavaScript memory leaks", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn what are the ways to avoid JavaScript memory leaks.
Brief introduction
Memory leaks are the ultimate problem that every developer has to face, and it is the root cause of many problems: slow response, crashes, high latency, and other application problems.
What is a memory leak?
In essence, a memory leak can be defined as when the application no longer needs to occupy memory, and for some reason, the memory is not reclaimed by the operating system or the available memory pool. Programming languages manage memory in different ways. Only the developer knows best which memory is not needed, and the operating system can recycle it. Some programming languages provide language features that can help developers do such things. Others hope that developers need to be clear about the need for memory.
JavaScript memory management
JavaScript is a garbage collection language. Garbage collection languages help developers manage memory by periodically checking whether previously allocated memory is reachable. In other words, garbage collection languages alleviate the problems of "memory is still available" and "memory is still reachable". The difference between the two is subtle and important: only developers know which memory will still be used in the future, while unreachable memory is determined and marked by algorithms and reclaimed by the operating system at the right time.
JavaScript memory leak
The main cause of memory leaks in garbage collection languages is unwanted references. Before you understand it, you also need to understand how the garbage collection language distinguishes between reachable and unreachable memory.
Mark-and-sweep
The algorithm used by most garbage collection languages is called Mark-and-sweep. The algorithm consists of the following steps:
The garbage collector creates a "roots" list. A Roots is usually a reference to a global variable in your code. In JavaScript, the "window" object is a global variable and is treated as a root. The window object always exists, so the garbage collector can check whether it and all of its children exist (that is, not garbage)
All roots are checked and marked as active (i.e. not junk). All child objects are also checked recursively. All objects starting with root are not treated as garbage if they are reachable.
All unmarked memory is treated as garbage, and the collector can now release the memory and return it to the operating system.
Modern garbage collectors improve the algorithm, but the essence is the same: reachable memory is marked and the rest is treated as garbage collection.
An unneeded reference means that the developer knows that the memory reference is no longer needed, but for some reason, it is still left in the active root tree. In JavaScript, an unwanted reference is a variable that remains in the code, which is no longer needed, but points to a piece of memory that should have been freed. Some people think it's the developer's fault.
To understand the most common memory leaks in JavaScript, we need to understand which way references are easily forgotten.
Three types of common JavaScript memory leaks
1: unexpected global variable
JavaScript handles undefined variables loosely: undefined variables create a new variable in the global object. In the browser, the global object is window.
Function foo (arg) {bar = "this is a hidden global variable";}
The truth is:
Function foo (arg) {window.bar = "this is an explicit global variable";}
The function foo forgot to use var inside and accidentally created a global variable. This example leaks a simple string, which is harmless, but there are worse cases.
Another unexpected global variable may be created by this:
Function foo () {this.variable = "potential accidental global";} / / Foo calls itself, and this points to the global object (window) / / instead of undefined foo ()
Add 'use strict',' to the header of the JavaScript file to avoid such errors. Enable strict mode parsing of JavaScript to avoid unexpected global variables.
Considerations for global variables
Although we have discussed some unexpected global variables, there are still some clear garbage generated by global variables. They are defined as non-recyclable (unless they are defined as empty or reassigned). Especially when global variables are used to temporarily store and process large amounts of information, you need to be careful. If you have to use global variables to store large amounts of data, be sure to set it to null or redefine it when you run out of it. One of the main reasons for increased memory consumption associated with global variables is caching. Caching data is for reuse, and the cache must have a size limit to be useful. High memory consumption causes the cache to break the limit because the cache content cannot be reclaimed.
2: forgotten timer or callback function
It is very common to use setInterval in JavaScript. A common piece of code:
Var someResource = getData (); setInterval (function () {var node = document.getElementById ('Node'); if (node) {/ / processing node and someResource node [XSS _ clean] = JSON.stringify (someResource));}}, 1000)
What this example shows: timers associated with nodes or data are no longer needed, node objects can be deleted, and the entire callback function is no longer needed. However, the timer callback function is still not recycled (the timer is not recycled until the timer stops). At the same time, someResource cannot be recycled if it stores a large amount of data.
In the case of observers, it is important to remove them explicitly once they are no longer needed (or the associated objects become unreachable). The old IE 6 couldn't handle circular references. Today, even if they are not explicitly removed, most browsers can recycle observer handlers once the observer object becomes unreachable.
Observer code example:
Var element = document.getElementById ('button'); function onClick (event) {Element [XSS _ clean] =' text';} element.addEventListener ('click', onClick)
Considerations for object watchers and circular references
Older versions of IE were unable to detect circular references between DOM nodes and JavaScript code, resulting in memory leaks. Today, modern browsers, including IE and Microsoft Edge, use more advanced garbage collection algorithms to detect and handle circular references correctly. In other words, you don't have to call removeEventListener when you reclaim node memory.
3: break away from the citation of DOM
Sometimes it is useful to preserve the internal data structures of DOM nodes. If you want to update several rows of the table quickly, it makes sense to save each row of DOM as a dictionary (JSON key-value pair) or an array. At this point, there are two references to the same DOM element: one in the DOM tree and the other in the dictionary. When you decide to delete these lines in the future, you need to clear both references.
Var elements = {button: document.getElementById ('button'), image: document.getElementById (' image'), text: document.getElementById ('text')}; function doStuff () {image.src =' http://some.url/image'; button.click (); console.log (text [XSS _ clean]) / / more logic} function removeButton () {/ / the button is the descendant element document.body.removeChild (document.getElementById ('button')) of body; / / at this point, there is still a global # button reference / / elements dictionary. The button element is still in memory and cannot be recycled by GC. }
Also consider references within the DOM tree or child nodes. Suppose you have a reference to a table in your JavaScript code. When you decide to delete the entire table in the future, it is intuitive that GC will recycle nodes other than those that have been saved. This is not the case: this is the child node of the table, and the child element has a reference relationship with the parent element. Because the code retains the reference, the entire table remains in memory. Be careful when saving DOM element references.
4: closure
Closures are a key aspect of JavaScript development: anonymous functions can access variables in the parent scope.
Code example:
Var theThing = null; var replaceThing = function () {var originalThing = theThing; var unused = function () {if (originalThing) console.log ("hi");}; theThing = {longStr: new Array (1000000). Join ('*'), someMethod: function () {console.log (someMessage);}}; setInterval (replaceThing, 1000)
The code snippet does one thing: each time you call replaceThing, theThing gets a new object that contains a large array and a new someMethod. At the same time, the variable unused is a closure that references originalThing (the previous replaceThing also called theThing). Are you confused? The most important thing is that once the scope of closures is created, they have the same parent scope, and the scope is shared. SomeMethod can be used through theThing, and someMethod shares the closure scope with unused, although unused has never been used, and its referenced originalThing forces it to remain in memory (to prevent it from being recycled). When this code runs over and over again, you will see that the memory footprint continues to rise, and the garbage collector (GC) does not reduce the memory footprint. In essence, a linked list of closures has been created, and each closure scope carries an indirect reference to a large array, causing a serious memory leak.
Meteor's blog post explains how to fix this problem. Add originalThing = null in * of replaceThing.
Overview of Chrome memory profiling tools
Chrome provides a great set of tools to detect the memory footprint of JavaScript. Two important tools related to memory: timeline and profiles.
Timeline
Timeline can detect unwanted memory in the code. In this screenshot, we can see the steady growth of potential leaked objects. At the end of data collection, the memory footprint is significantly higher than that at the initial stage of data collection, and the total amount of Node (nodes) is also very high. There are signs that there is a DOM node leak in the code.
Profiles
Profiles is a tool that you can spend a lot of time following. It can save snapshots, compare different snapshots of memory usage in JavaScript code, and record time allocations. Each time the result contains a different type of list, and the ones associated with memory leaks are summary list and comparison list.
The summary list shows the allocation and total size of different types of objects: shallow size (the total size of all objects of a particular type) and retained size (shallow size plus other associated object sizes). It also provides a concept of the distance between an object and the associated GC root.
Comparing the comparison list of different snapshots can reveal memory leaks.
Example: using Chrome to discover memory leaks
There are essentially two types of leaks: leaks caused by periodic memory growth, and occasional memory leaks. Obviously, periodic memory leaks are easy to detect; occasional leaks are tricky and generally easy to ignore, occasional leaks may be considered optimization problems, and periodic ones are considered bug that must be resolved.
Take the code in the Chrome document as an example:
Var x = []; function createSomeNodes () {var div, I = 100, frag = document.createDocumentFragment (); for (; I > 0; iMurb -) {div = document.createElement ("div"); div.appendChild (document.createTextNode (I + "-" + new Date (). ToTimeString ()); frag.appendChild (div);} document.getElementById ("nodes") .appendChild (frag) } function grow () {x.push (new Array (1000000). Join ('x')); createSomeNodes (); setTimeout (grow,1000);}
When the grow executes, start creating the div node and inserting it into the DOM, and assign a large array to the global variables. A steady increase in memory can be detected through the tools mentioned above.
Find out the memory that grows periodically
Timeline tags are good at doing this. Open the example in Chrome, open Dev Tools, switch to timeline, check memory and click the record button, and then click the The Button button on the page. Stop recording after a while and look at the results:
There are two signs of a memory leak, Nodes (green line) and JS heap (blue line) in the figure. Nodes is growing steadily, but not falling, which is a significant sign.
JS heap's memory footprint is also growing steadily. Due to the influence of garbage collector, it is not so easy to find. The figure shows that memory usage rises and falls. In fact, after each decline, the size of the JS heap is larger than before. In other words, although the garbage collector continues to collect memory, memory is leaked periodically.
After determining that there is a memory leak, let's find out what the root cause is.
Save two snapshots
Switch to the profiles tab of Chrome Dev Tools, refresh the page, and when the page refresh is complete, click Take Heap Snapshot to save the snapshot as a benchmark. Then click the The Button button again and wait a few seconds to save the second snapshot.
Select Summary on the filter menu, select Objects allocated between Snapshot 1 and Snapshot 2 on the right, or select Comparison on the filter menu, and you can see a comparison list.
It's easy to find memory leaks in this example. Take a look at (string) Size Delta Constructor,8MB,58 new objects. The new object is assigned, but not released, occupying the 8MB.
If you string Constructor, you will see many separate memory allocations. Choose a separate allocation and the following retainers will attract our attention.
The allocation we have selected is part of an array that is associated with the x variable of the window object. This shows the full path from a huge object to a root (window) that cannot be recycled. We have found the potential leak and its origin.
Our example is fairly simple, leaking only a small number of DOM nodes, which are easy to find using the snapshots mentioned above. For larger websites, Chrome also provides Record Heap Allocations functionality.
Record heap allocations looks for memory leak
Go back to the profiles tab of Chrome Dev Tools and click Record Heap Allocations. When the tool is running, pay attention to the blue bar at the top, which represents memory allocation, with a large amount of memory allocation each second. Stop after a few seconds of running.
You can see the killer mace of the tool in the image above: select a timeline and you can see the memory allocation for this time period. Choose a timeline as close to the peak as possible, and the following list shows only three types of constructor: one is the most leaked (string), the next is the associated DOM allocation, and the other is Text constructor (the text contained in the DOM leaf node).
Select a HTMLDivElement constructor from the list, and then select Allocation stack.
Now that you know where the elements are assigned (grow-> createSomeNodes), take a closer look at the timeline in the figure and find that HTMLDivElement constructor has been called many times, which means that memory has been occupied and cannot be reclaimed by GC. We know exactly where these objects are allocated (createSomeNodes). Go back to the code itself and explore how to fix memory leaks.
Another useful feature
In the result area of heap allocations, select Allocation.
This view presents a list of functions related to memory allocation, and we immediately see grow and createSomeNodes. When selecting grow, look at the relevant object constructor and clearly see (string), HTMLDivElement and Text leaked.
At this point, I believe you have a deeper understanding of "what are the ways to avoid JavaScript memory leaks?" you might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.