JavaScript内存优化

最近公司项目即将上线,Bug清得差不多了,跑了下项目发现内存占用很高。就研究了一下JS的内存机制,顺便学习了一手JS内存泄漏分析,在这里记录一下方便以后回顾,希望各位大佬提出建议,帮助小老弟提升,本文前提默认读者具备相应的计算机基础知识:包括对堆栈的理解,引用类型值类型的区别等。

JavaScript的内存管理机制:

不像C语言一样有自己的底层内存管理接口,比如malloc()和free()。JS在新建变量(对象,字符串等)时由系统自动分配内存,在不再使用变量时“自动”释放内存,即JS的垃圾回收机制。

如果规范地进行开发,得益于自动的垃圾回收机制程序员大多不用关心JS的内存管理,但难免会有一些不规范的操作造成内存的泄漏,所以还是有必要注意一下JS的内存使用。

程序运行必定要使用一定的内存,程序在申明变量的时候系统会自动给他们分配内存,程序使用变量往下执行直到退出即使用内存,程序完成一系列操作,用于这些操作的变量不再使用后即应该回收内存。

内存泄露即是指当一块内存不再被应用程序使用的时候,由于某种原因,这块内存没有返还给操作系统或者内存池的现象。可以想象,如果一个操作只分配内存而不回收,程序面临的结果必然时卡顿甚至是崩溃。

通俗理解就是新开一个标签进行操作之后,关闭标签之后内存的占用应该是趋于新开标签之前的水平,而不是应该有显著地增长。

首先来看一下JS垃圾回收的机制,只有先明白了垃圾回收的原理之后才能明白内存为什么没有正常的被回收。

1.引用计数法,这是最初级的垃圾回收算法

即一个对象是否有指向它的引用,如果没有其他对象指向它了,即说明这个对象是不再需要的了,可以被垃圾回收了。

var p={name:"tom",age:18}; //系统为这个对象(假定称为person)分配了内存,person被赋值给p,即被p给引用,这时这个person不会被回收
var q=p; //将p赋值为q,即又添加了一个对person的引用,即现在person被p和q引用
p="whatever";  //将p赋值为其他值,p不再对person有引用,现在只有q维持着对person的引用,这时这个person仍然不会被回收
q=null; //将q赋值为null,此时person已没有任何指向它的引用,现在可以被垃圾回收了

由此可见,使用完变量后赋值为null是一个好习惯。

这种垃圾回收模式简单易懂,相信大家一眼就能看明白。但是细心的华生可能已经发现了盲点,如果变量之间出现了循环引用怎么办呢?比如:

function dosomething(){
  var p= {};
  var q = {};
  p.prop = q; // p引用q
  q.prop = p; // q引用p
  ...
  return "result";
}
 
dosomething();

这里程序调用这个函数后,按理来说p和q已经不再需要了,但是由于他们相互引用,所以按照引用计数法两个变量都不能被垃圾回收。

为了解决循环引用造成的问题,现代浏览器通过使用标记清除算法来实现垃圾回收。

2.标记清除法:

标记清除算法将“不再使用的对象”定义为“无法达到的对象”。简单来说,就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。

凡是能从根部到达的对象,都是还需要使用的。那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。

从这个概念可以看出,无法触及的对象包含了没有引用指向的对象(没有任何引用的对象也是无法触及的对象),但反之未必成立。如上图中根据标记清除法,对象9、10、11是无法从GC根触及到的,所以它们会被打上标记,随后被垃圾回收器回收。

明白了JS垃圾回收的机制后,我们就初步可以得出结论:

内存泄漏即是用完对象后由于某些原因导致GC根或GC根可及的对象仍然维持对此对象的引用,导致对象不能及时被垃圾回收,所造成的内存不断增长的现象。

最简单的例子就是声明的全局变量,由于window对象是GC根的一种,如果不小心声明了全局变量并且在使用完之后没有将其赋值为null,则此变量一直不会被垃圾回收器回收。

所以千万要慎用全局变量,以及在声明变量时不要忘记使用var。

知道垃圾回收原理可以帮助我们在开发时减少意外地造成内存泄漏,常见的内存泄漏操作主要包括:

1.意外的全局变量;

2.被遗忘的定时器和回调函数;

3.不恰当的闭包;

4.脱离Dom的引用;

每种情况对应的详情大家可参考大神的文章--JS从内存空间谈到垃圾回收机制

既然有这么多可能造成内存泄漏的情况,那我们如何发现或者定位我们程序中的纰漏呢。

“我之所以看得更远,是因为我站在巨人的肩膀上!”--艾萨克·牛顿,当然不能一句一句地看代码,我们需要借助一些现成的工具。

这里推荐使用chrome自带的Performance和Memory工具,使用起来十分方便,详细使用教程参见大神的文章--chrome内存分析工具

最后如何避免内存泄漏情况的发生,总结一句话:不用的东西,及时归还

posted @ 2021-03-16 16:30  松树住松鼠  阅读(334)  评论(0编辑  收藏  举报