JavaScript中常见的内存泄露问题
JavaScript中常见的内存泄露问题
在此记录一下内存泄漏问题的发生
概念:
应用程序不再需要占用内存的时候,由于某些原因,内存没有被操作系统或可用内存池回收,就叫做内存泄漏(memory leak)
内存的生命周期
1.内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
2.内存使用:即读写内存,也就是使用变量、函数等
3.内存回收:使用完毕,由垃圾回收机制自动回收不再使用的内存
垃圾回收机制
对垃圾回收算法来说,核心思想就是如何判断内存已经不再使用了
分为两个方法:标记清除法和引用计数法
方法一 :标记清除法(mark-and-sweep),有三个步骤 :
1.垃圾回收器生成一个根列表。根通常是将引用保存在代码中的全局变量。在JavaScript中,window对象是一个可以作为根的全局变量。
2.所有的根都被检查和标记成活跃的(不是垃圾),所有的子变量也被递归检查。所有可能从根元素到达的都不被认为是垃圾。
3.所以没有被标记成活跃的内存都被认为是垃圾。垃圾回收器就可以释放内存并且把内存还给操作系统。
当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
function test(){ var a = 10 ; // 被标记 ,进入环境 var b = 20 ; // 被标记 ,进入环境 } test(); // 执行完毕 之后 a、b又被标离开环境,被回收。
方法一 :引用计数法(reference counting):
语言引擎有一张"引用表",保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放(被回收)。
const arr = [1, 2, 3, 4] // 数组[1, 2, 3, 4]是一个值,会占用内存。变量arr是仅有的对这个值的引用,因此引用次数为 1 // 尽管后面的代码没有用到arr,它还是会持续占用内存 arr = null // arr重置为null,就解除了对[1, 2, 3, 4]的引用,引用次数变成了0,内存就可以释放出来了
此处借鉴博客地址:
原文链接:https://blog.csdn.net/fu983531588/article/details/89465707
1.意外的全局变量
function Person(name) { this.name = name; } function test() { //使用let或var对变量进行声明 //当函数执行完毕后,p1,p2将被释放 let p1 = new Person("小明"); var p2 = new Person("小方"); //不使用任何关键字对变量进行声明 //此时该变量对被赋值到window对象上,导致它无法被释放 p3 = new Person("小红"); debugger;//在此处打断点 } test();
在内存未执行完之前,是有三个变量p1,p2,p3
当内存执行完(断点释放后),只剩变量p3
解决方法:在JavaScript程序中添加,开启严格模式’use strict’,可以有效地避免上述问题。
如果必须使用全局变量存储大量数据时,确保用完以后把它设置为 null 或者重新定义
2.被遗忘的定时器
function Person(name) { this.name = name; } function sayHello() { let p1 = new Person("悟空"); let p1 = new Person("八戒"); let p1 = new Person("唐僧"); console.log(p1.sayHello()); console.log(p2.sayHello()); let count = 0; setInterval(() => { if (count < 3) { //"唐僧"重复三次 console.log(p3.sayHello()); count++; } },100); } sayHello();
执行完后发现p3还存在,没有被销毁;
是因为定时器setInterval执行后没有被销毁,导致p3也没有被销毁。
解决方法:在合适的时间销毁定时器
function Person(name) { this.name = name; } function sayHello() { let p1 = new Person("悟空"); let p1 = new Person("八戒"); let p1 = new Person("唐僧"); console.log(p1.sayHello()); console.log(p2.sayHello()); let count = 0; let intervalId = setInterval(() => { //给定时器一个名字 if (count < 3) { //"唐僧"重复三次 console.log(p3.sayHello()); count++; }else { clearInterval(intervalId); //此处销毁定时器 } },100); } sayHello();
3.脱离DOM的元素引用
var A = document.getElementById('A'); document.body.removeChild(A); //remove方法只是将A从DOM上面移除了,但并没有从内存当中移除。
解决方法:添加 A = null; 手动将变量指为空值即可。
4.闭包引起的内存泄露
window.onload = function(){ var el = document.getElementById("id"); el.onclick = function(){ alert(el.id); } } 解决方法为 window.onload = function(){ var el = document.getElementById("id"); var id = el.id; //解除循环引用 el.onclick = function(){ alert(id); } el = null; // 将闭包引用的外部函数中活动对象清除 }
- 点赞
- 收藏
- 分享
- 文章举报
- Java常见问题分析(内存溢出、内存泄露、线程阻塞等)
- 一个常见的android内存泄露 问题
- javascript中内存泄露问题的解决方案
- JavaScript 中 4 种常见的内存泄露陷阱
- 谈谈.NET中常见的内存泄露问题——GC、委托事件和弱引用
- 谈谈.NET中常见的内存泄露问题——GC、委托事件和弱引用
- Java中最常见的10个性能问题(05):内存泄露
- android内存泄漏---常见内存泄露的问题
- 谈谈.NET中常见的内存泄露问题——GC、委托事件和弱引用
- 用Chrome-Profiles检查Javascript内存泄露问题
- JavaScript是如何工作的:内存管理 + 如何处理4个常见的内存泄露
- JavaScript Memory Leaks(js内存泄露的问题)
- 总结JavaScript在IE9之前版本中内存泄露问题
- 谈谈.NET中常见的内存泄露问题——GC、委托事件和弱引用
- .NET中常见的内存泄露问题——GC、委托事件和弱引用
- Java常见问题分析(内存溢出、内存泄露、线程阻塞等)
- 常见的 JavaScript 内存泄露
- silverlight内存问题总结(二)—javascript内存泄露