(自用面试题)导致内存泄漏的情况有哪些?

482 阅读2分钟

内存泄漏(Memory Leak)的定义:
程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须供给内存。对于持续运行的服务进程,必须及时释放不再用到的内存,否则内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
内存泄漏(Memory Leak)是指在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存,并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

  1. 意外的全局变量:由于使用未声明的变量而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。

eg:

// 此时解释器会把变量bar当作window的属性来创建(相当于window.variable = 'this is a hidden global variable')
function foo(arg) {
    variable = 'this is a hidden global variable';
}

另一种意外的全局变量可能由this创建:
eg:

function foo() {
    this.variable = 'this is a hidden global variable';
}
// foo()调用自己,this指向了全局对象(window)
foo();
  1. 被遗忘的定时器或回调函数:设置了setInterval()定时器而忘记取消它,如果循环函数的引用的话,那么这个变量一直留在内存中无法被回收。

eg:

// 定时器通过闭包引用了外部变量,只要定时器一直运行,回调函数引用的name就会一直占用内存
let name = 'Jake';
setInterval(() => {
  console.log(name);
}, 100);
  1. 不合理的使用闭包

eg:

// 下面代码执行后创建了一个内部闭包,只要返回的函数存在就不能清理name,因为闭包一直在引用它
let outer = function() {
  let name = 'Jake';
  return function() {
    return name;
  };
};
  1. 脱离DOM的引用:获取一个DOM元素的引用,而后面这个元素被删除,但由于一直保留了对这个元素的引用,所以它也无法被回收。

eg:

const refA = document.getElementById('refA');
document.body.removeChild(refA); // 删除DOM
console.log(refA, 'refA'); // 但是还存在引用,能console.log出整个div,没有被回收
refA = null;
console.log(refA, 'refA'); // 解除引用,内存回收