什么是内存泄露?

  任何编程语言,在运行时都需要使用到内存,比如在一个函数中, var arr = [1, 2, 3, 4, 5]; 这么一个数组,就需要内存。

  但是,在使用了这些内存之后, 如果后面他们不会再被用到,但是还没有及时释放,这就叫做内存泄露(memory leak)。如果出现了内存泄露,那么有可能使得内存越来越大,而导致浏览器崩溃。

  C语言是通过手动分配和释放内存的, 如通过malloc分配,通过free释放,这种方式是比较麻烦的。而java、c#、js等是为了解放程序员的负担,提出了程序自动释放内存,这种方式就是垃圾回收机制

JavaScript中的两种垃圾回收机制

  在js中,有引用计数和标记清除这两种垃圾回收机制

引用计数

  即跟踪记录每个值被引用的次数,当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1; 相反,如果包含对这个值引用的变量又取得了另外一个值,那么这个值的引用次数就减1;当引用次数变为0的时候,则说明没有办法再访问到这个值了,所以,就可以把其所占用的内存空间给收回来。 这样,垃圾收集器下次再运行时,他就会释放哪些引用次数为0的值所占的内存。

  但是,引用计数还是会存在问题的:

function problem() {
var objA = new Object();
var objB = new Object(); objA.someOtherObject = objB;
objB.anotherObject = objA;
}

  如上所示,objA指向内存中的引用类型,而这个引用类型的一个值又指向了另一个引用类型,这样,每个引用类型的引用次数都是2,且在引用类型之间形成了循环引用,这样,即使problem()函数执行完毕,把后期不再使用的局部变量objA和objB释放,但是因为引用类型的引用次数还是1,那么这两个引用类型还是不能被释放的,这就造成了内存泄露。 如下图所示:

  所以说,我们所说的循环引用实际上是在堆中的两个引用类型之间的循环引用,如右边的两个箭头就构成了一个循环。

  另外,由于BOM和DOM中的对象是使用C++以COM(Component Ojbect Model,组件对象)对象的形式实现的,而COM对象的垃圾回收机制是引用计数。 因此,即使IE的JavaScript引擎使用的是标记清除的策略,但是JavaScript访问的COM对象依然是基于引用计数的策略的,说白了,只要IE中涉及到了COM对象,就会存在循环引用的问题。 如下:

var element = document.getElementById("some_element");
var myObj =new Object();
myObj.element = element;
element.someObject = myObj;

  这个例子中,一个DOM元素和一个原生JavaScript对象之间建立了循环引用。这样,即使例子中的DOM从页面中移除,内存也不会被回收,但是,我们可以手动切断他们的循环引用:

myObj.element = null;
element.someObject =null;

  这样写代码就可以解决循环引用的问题,也就防止了内存泄露的问题了。

标记清除

  这是JavaScript中最常用的垃圾回收机制。当变量进入环境时,就标记这个变量为“进入环境”,逻辑上说,永远不能释放进入环境的变量所占用的内存,因为一旦进入环境就有可能随时用到他们,当变量离开环境的时候,将其标记为“离开环境”。 

 

区别:可以看到,引用计数是实时的,即只要引用数为0,就会清除这变量,而标记清除是添加上标记之后,每隔一段时间回收哪些添加了离开环境标记的变量。

使用情况:不同的浏览器可能采用的回收机制不同,比如有的可能全部使用引用计数,有的全部使用标记清除。 但是,BOM、DOM采用的一定都是引用计数。

几种常见的JavaScript 内存泄露

1、意外的全局变量

  function foo(arg) {
bar = "this is a hidden global variable";
}

bar没有使用var来声明,所以实际上这里就相当于 window.bar = 'this is a hidden global variable'。 但是在函数中使用的变量,我们往往是希望只在函数中使用,而一旦函数执行完毕就清除这个变量,但是这种意外的全局变量就会导致直到程序执行完毕,才会释放,即导致了内存泄露。

另外一种方式如下:

  function foo() {
this.variable = "potential accidental global";
}
// Foo called on its own, this points to the global object (window)
// rather than being undefined.
foo();

即一般的函数调用,this是指向全局的,所以,也是一个全局变量了,即内存泄露。

因此,对于局部使用的变量,为了不会造成内存泄露,我们最好使用var来声明。

2、循环引用造成的内存泄露。

  之前的例子提到过,对于引用类型之间的循环引用,会造成内存泄露,所以,我们可以手动解除。

3、 删除元素造成的内存泄露

  <div id="wrap">
<span id="link">点击</a>
</div>
<script>
let wrap = document.getElementById('wrap');
link = document.getElementById('link');
function handleClick() {
alert('clicked');
}
link.addEventListener('click', handleClick ,false); wrap.removeChild(link);
document.body.appendChild(link);

在这个例子中,我们可以看到,即使link已经被移除了,然后我们通过appendChild添加到div平级的地方,然后点击之后还是有事件发生的,说明这里元素被移除然后添加,事件还是可以用的。

但是,我们已经将之移除了,所以,后面就不需要了,但是span标签还是被link变量所引用,这样,就造成了内存泄露。

所以,我们可以在link被移除的时候,就清楚这个引用,如下所示:

  <div id="wrap">
<span id="link">点击</a>
</div>
<script>
let wrap = document.getElementById('wrap');
link = document.getElementById('link');
function handleClick() {
alert('clicked');
}
link.addEventListener('click', handleClick ,false); wrap.removeChild(link);
link = null;

这样,其引用次数就是0了。 但是这里做法其实也不好,因为这个如果可以封装到一个函数中,函数结束,变量释放,自然也是可以解决这个问题的。。。

  

JavaScript中的垃圾回收机制与内存泄露的更多相关文章

  1. Chrome V8系列--浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略

    V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制.因此,V8 将内存(堆)分为新生代和老生代两部分. 一.前言 V8的垃圾回收机制:JavaScript使用垃圾回收机制来自动管理内存.垃圾 ...

  2. Javascript中的垃圾回收机制

    Javascript 中的内存管理 译自MDN,Memory Management 简介 在底层语言中,比如C,有专门的内存管理机制,比如malloc() 和 free().而Javascript是有 ...

  3. Java垃圾回收机制以及内存泄露

    1.Java的内存泄露介绍 首先明白一下内存泄露的概念:内存泄露是指程序执行过程动态分配了内存,可是在程序结束的时候这块内存没有被释放,从而导致这块内存不可用,这就是内存 泄露,重新启动计算机能够解决 ...

  4. JS基础-垃圾回收机制与内存泄漏的优化

    [V8引擎]浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略 垃圾回收机制 如何判断回收内容 如何确定哪些内存需要回收,哪些内存不需要回收,这是垃圾回收期需要解决的最基本问题.我们可以这样 ...

  5. 160930、Javascript的垃圾回收机制与内存管理

    一.垃圾回收机制-GC Javascript具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存. 原理:垃圾收集器会定期(周期性 ...

  6. JavaScript中的垃圾回收和内存泄漏

    摘要: JS内存管理. 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 程序的运行需要内存.只要程序提出要求,操作系统或者运行时就必须供给内存.所谓的内存泄漏简单来说是不再用到的 ...

  7. javascript的垃圾回收机制与内存管理

    一.垃圾回收机制—GC Javascript具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存. 原理:垃圾收集器会定期(周期性 ...

  8. JavaScript具有自动垃圾回收机制

    JavaScript具有自动垃圾回收机制 原理: 找出那些不再继续使用的变量,然后释放其占用的内存.   正常的生命周期:     局部变量指在函数执行的过程中存在.而在这个过程中,会为局部变量在栈或 ...

  9. 你不知道的JavaScript--Item28 垃圾回收机制与内存管理

    1.垃圾回收机制-GC Javascript具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存. 原理:垃圾收集器会定期(周期性 ...

随机推荐

  1. struts2 file

    JavaBean 中: private File[] pic; private String[] picContentType; private String [] picFileName; sett ...

  2. x13 vs md5

    x13 vs md5 阅读:  评论:  作者:Rybby  日期:  来源:rybby.com 最近在设计巴巴变时想对用户设计的节点模块添加锁定功能,比如你的网站可以让用户发表文章或评论,而你想让用 ...

  3. java web代码规范:

    每个类前要有注释,类前的注释格式是: /** *类是干什么的 *@author  编写该类的作者 */ 类中的每个方法前也要有注释: /** *该方法是干什么的 *@param 该方法中传入的参数 * ...

  4. [jquery-delegate] iphone_4s _iphone _5c_中不兼容jQuery delegate 事件(does not wok)

    1. jQuery .on() and .delegate() doesn't work on iPad http://stackoverflow.com/questions/10165141/jqu ...

  5. 【WP8.1】页面的导航效果

    <Page.Transitions> <TransitionCollection> <NavigationThemeTransition> <CommonNa ...

  6. AbpZero之企业微信---登录(拓展第三方auth授权登录)---第一步:查看AbpZero的auth第三方登录的底层机制

    在AbpZero框架中,auth登录接口位于Web.Core库下的Controllers文件夹的TokenAuthController.cs的ExternalAuthenticate方法 Extern ...

  7. HTTP响应状态码说明

    当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(Server Header)用以响应浏览器的请求. HTTP状态码共分为五种类型: 1**:信息,服务器接收到请求,需 ...

  8. JavaScript原型与继承的秘密

    在GitHub上看到的关于JavaScript原型与继承的讲解,感觉很有用,为方便以后阅读,copy到自己的随笔中. 原文地址:https://github.com/dreamapplehappy/b ...

  9. wpf使用DynamicDataDisplay插件,修改x轴的样式,改成透明的。

    时光偷走的,永远都是我们眼皮底下看不见的珍贵. 问题:X轴会显示灰色拖动条. 解决:将X轴颜色改为透明. DDD插件是开源的,但是网上的参考资料却很少,所以,很多问题在网上搜索不到,因为没有找到该插件 ...

  10. 基于GitLab与Git Extensions搭建版本控制工具

    1.背景 大家知道GitHub是现在非常流行的代码托管工具,但是如果有些项目不想开源的话,则需要付费,因此萌生了自己搭建一个Git的版本控制工具,供内网使用.GitLab则是个好的选择,但是GitLa ...