您好,欢迎来到伴沃教育。
搜索
您的当前位置:首页内存泄漏及解决方案

内存泄漏及解决方案

来源:伴沃教育


什么是内存泄漏

在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

通俗点就是:内存泄漏就是一些可以避免的内存花销

常见的内存泄漏问题

闭包会引起内存泄漏?

不一定,闭包是否产生内存浪费取决于 js 的垃圾回收机制是否将变量占用的内存给及时清除掉,常见的垃圾回收算法有标记清除法,能标记到就不回收,反之则回收。

  • 不会造成内存浪费的情况

一般如果闭包函数没有返回值或者没有使用全局变量对闭包函数的返回值进行存储,如下

function fn() {
    //fn 函数作用域的局部变量 arr
    const arr = new Array(10000000)
    function fn1() {
        // 在 fn1 函数作用域下访问(依赖)外层 fn 函数作用域的局部变量 arr,此时会产生闭包
        console.log(arr[0]);
    }
    fn1()
}
fn()

打开控制台进行断点查看:

打开控制台进行性能分析: 

  • 会造成内存浪费的情况

如果闭包函数存在返回值并且使用全局变量对闭包函数的返回值进行存储,如下

function fn() {
    const arr = new Array(10000000)
    function fn1() {
        console.log(arr[0]);
        return new Array(10000000)
    }
    return fn1
}
// 变量 test 由于保存了 fn1 函数的引用,
// 而 fn1 函数作用域内又依赖于 fn 作用域的Array(10000000),变量 arr 同理
// 所以导致Array(10000000)在堆内存中无法被释放
let test = fn()
let arr = test()

打开控制台进行断点查看:

打开控制台进行性能分析:

80mb大概就是两个 Array(10000000)的内存大小,因为全局变量 test,arr 一直保持对Array(10000000)的引用,所以导致 js 垃圾回收机制无法回收

解决方法:可以使变量赋值为 null

function fn() {
    const arr = new Array(10000000)
    function fn1() {
        console.log(arr[0]);
        return new Array(10000000)
    }
    return fn1
}
// 变量 test 由于保存了 fn1 函数的引用,
// 而 fn1 函数作用域内又依赖于 fn 作用域的Array(10000000),变量 arr 同理
// 所以导致Array(10000000)在堆内存中无法被释放
let test = fn()
let arr = test()
test = null
arr = null

打开控制台进行性能分析:

意外的全局变量

解决方法:使用 var、let 或 const 关键字声明所有的变量,并在不再需要时及时释放它们

function init() {
  // create local variable
    // myvar = 'hello world'  没有用 var 申明,导致变成全局变量
  var myVar = 'hello world';
 
  // add event listener to DOM element
  document.getElementById('myButton').addEventListener('click', function() {
    // do something with myVar
  });
 
  // myVar is no longer needed and will be garbage collected
  myVar = null;
}
定时器未清除引起的内存泄露

在使用 JavaScript 定时器时,如果不及时清除定时器,那么它将继续存在并持有内存。这是因为定时器仍然在等待计时器到达指定的时间,这可能会导致内存泄漏。

解决方法:在不再需要定时器时,手动清除它

var timer = setInterval(function() {
  // do something
}, 1000);
 
// clear timer when it's no longer needed
clearInterval(timer);
循环引用引起的内存泄露

当两个或更多对象相互引用时,就会出现循环引用。如果其中一个对象被删除,它仍然被其他对象引用,这可能会导致内存泄漏。

解决方法:在不需要对象时,手动解除相互引用

var obj1 = {};
var obj2 = {};
 
obj1.ref = obj2;
obj2.ref = obj1;
 
// remove references to obj1 and obj2 when they're no longer needed
obj1.ref = null;
obj2.ref = null;
obj1 = null;
obj2 = null;
DOM泄露

获取到 DOM 节点之后,将 DOM 节点删除,但是没有手动释放变量,那对应的 DOM 节点在变量中还可以访问到,就会造成泄露。

解决方法:在不需要的时候手动解除对外部变量的引用

function createClosure() {
  var element = document.getElementById('myElement');
  return function() {
    // do something with element
    element = null; // remove reference to element
  };
}
 
var closure = createClosure();
 
// element is no longer referenced and can be garbage collected

前端常见内存泄露检测工具

以下是几个常见的前端内存泄漏检测工具:

  • Chrome开发者工具

Chrome浏览器的开发者工具提供了内存分析工具,可以检查应用程序中所有的JavaScript对象,显示它们的引用关系、内存占用情况等信息。在Chrome开发者工具中,可以通过“Memory”选项卡来检测内存泄漏问题。

  • Heapdump

Heapdump是一个Node.js模块,用于生成堆快照,并提供了一个用于检查内存泄漏的Web界面。Heapdump可以在运行时捕获应用程序的堆快照,并将其保存到文件中。然后可以使用Chrome开发者工具或其他工具来分析堆快照中的数据。

  • LeakChecker

LeakChecker是一款基于Chrome开发者工具的内存泄漏检测工具,可以检测JavaScript应用程序中的内存泄漏问题。LeakChecker跟踪页面中所有的JavaScript对象,并生成报告以帮助用户解决问题。

  • Lighthouse

Lighthouse是一款由Google开发的工具,可以用于检查Web应用程序的性能和可访问性。Lighthouse提供了内存分析工具,可以检查JavaScript对象的内存占用情况,并生成报告以帮助用户解决问题。

  • DevTools Timeline

DevTools Timeline是Chrome开发者工具中的一个工具,可以用于检查应用程序的性能和内存使用情况。DevTools Timeline跟踪页面中所有的JavaScript对象,并显示它们的内存占用情况。使用DevTools Timeline,开发者可以检查应用程序中的内存泄漏问题,并进行优化。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- bangwoyixia.com 版权所有 湘ICP备2023022004号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务