美文网首页
javascript 内存泄露

javascript 内存泄露

作者: _一九九一_ | 来源:发表于2019-12-09 17:54 被阅读0次

js内存溢出


JS程序的内存溢出后,表现为程序突然卡死假死报错

内存生命周期


  • 分配你所需要的内存(变量、函数、对象执行时内存)
  • 使用分配到的内存(读、写)
  • 不需要时将其释放\归还(只回收局部变量,全局变量的生命周期直至浏览器卸载页面才会结束)

如时执行回收


  • 局部变量只在函数的执行过程中存在,会为局部变量在栈或堆上分配相应的空间,以存储它们的值,然后在函数中使用这些变量,直至函数结束然后回收。
  • 而闭包中由于内部函数的原因,外部函数并不能算是结束。

几种常见的js内存泄露


  1. 全局变量泄漏,调用的时候 this 指向了全局对象(window)
  2. 没有及时清理的计时器或回调函数
  3. 闭包, 事件处理回调,导致DOM对象和脚本中对象双向引用,这个时常见的泄漏原因
  4. script 中存在对DOM/BOM 对象的互相引用导致

例子


  • f1函数
    被调用时,进入fn1环境,开辟一块内存存放对象{name: 'aaa', age: 10},而当调用结束后,出了fn1的环境,该块内存会被js引擎中的垃圾回收器自动释放
  • f2函数
    在fn2被调用,返回的对象被全局变量b所指向,该块内存并不会被释放
function fn1() {
    var obj = {name: 'aaa', age: 10};
}
function fn2() {
    var obj = {name:'bbb', age: 10};
    return obj;
}

var a = fn1();
var b = fn2();

垃圾收集器是怎么判断哪个变量要回收( 标记清除和引用计数 )


标记清除和引用计数

  • 引用计数不太常用,标记清除较为常用。
  • 遍历所有可访问的对象。
  • 回收已不可访问的对象。

标记清除

  • 算法假定设置一个叫做根(root)的对象,垃圾回收器将定期从根开始扫描内存中的对象。能从根部到达的对象,都是还需要使用的不回收。那些无法由根部出发触及到的对象被标记(标记阶段)为不再使用,进行回收。

  • 此算法可以分为两个阶段,一个是标记阶段(mark),一个是清除阶段(sweep)。

    1. 标记阶段,垃圾回收器会从根对象开始遍历。每一个可以从根对象访问到的对象都会被添加一个标识,于是这个对象就被标识为可到达对象。
    2. 清除阶段,垃圾回收器会对堆内存从头到尾进行线性遍历,如果发现有对象没有被标识为可到达对象,那么就将此对象占用的内存回收,并且将原来标记为可到达对象的标识清除,以便进行下一次垃圾回收操作。
    3. 在标记阶段,从根对象1可以访问到B,从B又可以访问到E,那么B和E都是可到达对象,同样的道理,F、G、J和K都是可到达对象。
    4. 所有未标记为可到达的对象都会被垃圾回收器回收
function test(){
  var a = 1 ;             // 被标记 ,进入环境 
  var b = 2 ;             // 被标记 ,进入环境
}
test();                     //执行完毕 之后 a、b又被标离开环境,被回收

到目前为止,IE9+、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。

引用计数

  • 该算法假定设置一个叫做根(root)的对象,垃圾回收器将定期从根开始扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的。那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。
  • 有一个严重的问题:循环引用。
  • 循环引用指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用。
  • 如果fn函数被大量调用,就会造成内存泄露。在IE7与IE8上,内存直线上升。
function test(){
    var a = {} ;         //a的引用次数为0 
    var b = a ;         //a的引用次数加1,为1 
    var c =a;           //a的引用次数再加1,为2
    var b ={};          //a的引用次数减1,为1
}

function fn() {
    var a = {};
    var b = {};
    a.pro = b;
    b.pro = a;
}
fn();

GC根


  • 一般指全局且不会被垃圾回收的对象,比如:window、document或者是页面上存在的dom元素。
  • JavaScript的垃圾回收算法会判断某块对象内存是否是GC根可达(存在一条由GC根对象到该对象的引用),如果不是那这块内存将会被标记回收。

GC的缺陷


  • GC时,会停止响应其他操作,这是为了安全考虑。
  • 这就是新引擎需要优化的点:避免GC造成的长时间停止响应

GC优化策略


Chrome V8 垃圾回收算法采用分代回收策略

  • 通过区分「临时」与「持久」对象
  • 多回收“临时对象”区,少回收“持久对象”区,减少每次需遍历的对象,减少每次GC的耗时

V8的内存限制

64位系统下,新生代内存大小为32MB,老生代内存大小为1.4GB。
32位系统新生代内存大小为16MB,老生代内存大小为700MB。

新生代内存:

  • 存储的为存活时间较短的对象

老生代内存

  • 存储的为存活时间较长或常驻内存的对象

相关文章

  • javascript 内存泄露

    js内存溢出 JS程序的内存溢出后,表现为程序突然卡死或假死或报错 内存生命周期 分配你所需要的内存(变量、函数、...

  • Javascript内存泄露

    常见的js内存泄露 1. 意外的全局变量 JavaScript 处理未定义变量的方式比较宽松:未定义的变量会在全局...

  • 内存泄露系列文章(一) - 内存泄露原因及影响

    前言 内存泄露系列文章内存泄露系列文章(一) - 内存泄露原因及影响内存泄露系列文章(二) - 内存泄露监测及分析...

  • 内存泄露系列文章(三) - 内存泄露解决方案

    前言 内存泄露系列文章内存泄露系列文章(一) - 内存泄露原因及影响内存泄露系列文章(二) - 内存泄露监测及分析...

  • Javascript 性能分析总结

    Javascript内存泄露参考Paul的文档:http://www.jianshu.com/p/0191c693...

  • 内存泄漏

    JavaScript 的垃圾收集机制内存泄露可以定义为:应用程序不再需要占用内存的时候,由于某些原因,内存没有被操...

  • JavaScript 内存溢出与内存泄露

    闭包的缺点 函数执行完之后,函数内的局部变量没有释放,占用内存的时间会变长。容易造成内存泄露。 上述代码没有释放a...

  • Javascript的垃圾回收机制

    为避免内存泄露,JavaScript 具有垃圾收集机制。 内存泄漏:指由于疏忽或错误造成程序未能释放已经不再使用的...

  • 内存溢出与内存泄露

    目录 [TOC] 1 内存泄露与内存溢出的区别 1.1 内存泄露 内存泄露(Memory Leak),指的是堆内存...

  • 内存泄露那些事

    在JavaScript中,由于编码者忽略或者不注意某些细节,经常会造成内存泄露。 首先,什么是内存泄漏?这是个什么...

网友评论

      本文标题:javascript 内存泄露

      本文链接:https://www.haomeiwen.com/subject/brxegctx.html