前端进阶之深入了解JS垃圾回收机制和内存泄漏

开发 前端
垃圾回收机制的原理是找到不再继续使用的变量,释放其内存。垃圾回收器会按照固定的时间间隔(或代码中预定的收集时间),周期性地执行这一操作;Javascript 会找出不再使用的变量,不再使用意味着这个变量生命周期的结束。

[[425597]]

本文转载自微信公众号「Android开发编程」,作者Android开发编程。转载本文请联系Android开发编程公众号。

前言

JS自带一套内存管理引擎,负责创建对象、销毁对象,以及垃圾回收。

我们来探讨一下垃圾回收机制和内存泄露;

一、垃圾回收机制详解

1、什么是js的回收机制

  • 垃圾回收机制的原理是找到不再继续使用的变量,释放其内存。垃圾回收器会按照固定的时间间隔(或代码中预定的收集时间),周期性地执行这一操作;
  • Javascript 会找出不再使用的变量,不再使用意味着这个变量生命周期的结束。Javascript 中存在两种变量——全局变量和局部变量,全部变量的声明周期会一直持续,直到页面卸载;
  • 而局部变量声明在函数中,它的声明周期从执行函数开始,直到函数执行结束。在这个过程中,局部变量会在堆或栈上被分配相应的空间以存储它们的值,函数执行结束,这些局部变量也不再被使用,它们所占用的空间也就被释放;
  • 垃圾回收的两种实现方式:标记清除、引用计数

2、标记清除(主流浏览器做法)

  • 主要思想是给当前不使用的值加上标记,然后再回收他的内存;
  • 垃圾回收器在运行时会给存储在内存中的变量加上标记,然后他会去掉环境变量和被环境变量引用的变量的标记,此后被加上标记的变量(环境变量中没有使用访问的变量)就是准备删除的变量;最后垃圾回收器完成清除工作,销毁那些带标记的值,并回收他们占用的内存空间;

标记和扫描算法经过:

  • 根节点:一般来说,根是代码中引用的全局变量;
  • 然后算法检查所有根节点和他们的子节点并且把他们标记为活跃的(意思是他们不是垃圾)。任何根节点不能访问的变量将被标记为垃圾;
  • 最后,垃圾收集器释放所有未被标记为活跃的内存块,并将这些内存返回给操作系统;

3、引用计数(IE9以下)

含义是跟踪记录所有值被引用的次数;

例如变量a赋值后,这个值的引用次数为1,这个a值又被赋值给另一个变量b,这时引用次数+1;但当b赋另外的值,引用次数-1;当值的引用书为0,说明没有办法再访问这个值,这时就可以将内存回收了。

IE9以下还在使用引用计数,当对象循环引用时,引用次数无法标记为0,就会导致无法被回收。其他浏览器废弃使用;

下面的代码

  1. var o1 = { 
  2.   o2: { 
  3.     x: 1 
  4.   } 
  5. }; 
  6. // 两个对象被创建。 
  7. // ‘o1’对象引用‘o2’对象作为其属性。 
  8. // 不可以被垃圾收集 
  9. var o3 = o1; // ‘o3’变量是第二个引用‘o1‘指向的对象的变量.  
  10. o1 = 1;      // 现在,在‘o1’中的对象只有一个引用,由‘o3’变量表示 
  11. var o4 = o3.o2; // 对象的‘o2’属性的引用. 
  12.                 // 此对象现在有两个引用:一个作为属性、另一个作为’o4‘变量 
  13. o3 = '374'; // 原来在“o1”中的对象现在为零,对它的引用可以垃圾收集。 
  14.             // 但是,它的‘o2’属性存在,由‘o4’变量引用,因此不能被释放。 
  15. o4 = null; // ‘o1’中最初对象的‘o2’属性对它的引用为零。它可以被垃圾收集。 

二、Js常见的内存泄漏

内存泄漏是应用程序过去使用,但不再需要的尚未返回到操作系统或可用内存池的内存片段。由于没有被释放而导致的,它将可能引起程序的卡顿和崩溃;

1、意外的全局变量

  1. function foo(arg) { 
  2.     bar = "test"
  3.     // window.bar = "test"

js对未声明变量会在全局最高对象上创建它的引用,(是以属性存在的,而不是变量),如果在游览器上就是window对象,如果在node环境下就是global;如果未声明的变量缓存大量的数据,它可能只有在页面被刷新或者被关闭的时候才会释放内存,这样就造成了内存意外泄漏;

2、被忘记的定时器或者回调函数

我们以经常在 JavaScript 中使用的 setInterval 为例;

  1. var serverData = loadData(); 
  2. setInterval(function() { 
  3.     var renderer = document.getElementById('renderer'); 
  4.     if(renderer) { 
  5.         renderer.innerHTML = JSON.stringify(serverData); 
  6.     } 
  7. }, 5000); //每5秒执行一次. 
  • 上面的代码片段显示了使用定时器引用节点或无用数据的后果。它既不会被收集,也不会被释放。无法被垃圾收集器收集,频繁的被调用,占用内存;
  • 而正确的使用方法是,确保一旦依赖于它们的事件已经处理完成,就通过明确的调用来删除它们;

3、闭包

  • 闭包是一个函数A返回一个内联的函数B,及时A函数执行完函数B也可以访问函数A里面的变量,这就是一个简单的闭包;
  • 本质上闭包是将函数内部和外部连接起来的一座桥梁;
  1. function my(name) { 
  2.     function sendName() { 
  3.         console.log(name
  4.     } 
  5.     return sendName 
  6. var test=my("test"
  7. test()  //test 

在my()内部创建的sendName()函数是不会被回收的,因为它被全局变量test引用,处于随时被调用的状态。如果向释放内存可以设置test=null;由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多

4、DOM泄漏

  • 浏览器中DOM和js采用的是不一样的引擎,DOM采用的是渲染引擎,而js采用的是v8引擎,所以在用js操作DOM时会比较耗费性能,因为他们需要桥来链接他们。为了减少DOM的操作,我们一般将常用的DOM;
  • 我们会采用变量引用的方式会将其缓存在当前环境。如果在进行一些删除、更新操作之后,可能会忘记释放已经缓存的DOM;
  1. var elements = { 
  2.     button: document.getElementById('button'), 
  3.     image: document.getElementById('image'
  4. }; 
  5. function doStuff() { 
  6.     elements.image.src = 'http://test.png'
  7. function removeImage() { 
  8.     // image 元素是body的直接子元素。 
  9.     document.body.removeChild(document.getElementById('image')); 
  10.     // 我们仍然可以在全局元素对象中引用button。换句话说,button元素仍在内存中,无法由GC收集 

总结

GC机制是自动完成的,但我们可以强制启动它,或是关闭它;

我们在开发中要注意内存泄露问题,不然会出现意想不到的情况;

 

一起学习加油;

 

责任编辑:武晓燕 来源: Android开发编程
相关推荐

2010-09-26 16:42:04

JVM内存组成JVM垃圾回收

2011-01-18 14:06:58

JavaScriptweb

2011-07-04 13:12:04

JavaScript

2009-12-09 17:28:34

PHP垃圾回收机制

2010-09-26 14:08:41

Java垃圾回收

2019-08-19 12:50:00

Go垃圾回收前端

2021-11-05 15:23:20

JVM回收算法

2019-09-12 09:30:50

Vue项目内存

2023-02-28 07:56:07

V8内存管理

2024-02-22 17:15:22

JS垃圾回收机制

2009-06-23 14:15:00

Java垃圾回收

2017-08-17 15:40:08

大数据Python垃圾回收机制

2010-09-25 15:33:19

JVM垃圾回收

2017-03-03 09:26:48

PHP垃圾回收机制

2010-09-26 11:22:22

JVM垃圾回收JVM

2011-06-28 12:39:34

Java垃圾回收

2015-06-04 09:38:39

Java垃圾回收机

2017-06-12 17:38:32

Python垃圾回收引用

2010-09-25 15:26:12

JVM垃圾回收

2010-09-16 15:10:24

JVM垃圾回收机制
点赞
收藏

51CTO技术栈公众号