美文网首页
JS学习笔记_内存泄露

JS学习笔记_内存泄露

作者: 哈哈哈我的简书账号 | 来源:发表于2020-09-03 16:53 被阅读0次
Mark-and-sweep
大部分垃圾回收语言用的算法称之为 Mark-and-sweep 。算法由以下几步组成:

垃圾回收器创建了一个“roots”列表。Roots 通常是代码中全局变量的引用。JavaScript 中,“window” 对象是一个全局变量,被当作 root 。window 对象总是存在,因此垃圾回收器可以检查它和它的所有子对象是否存在(即不是垃圾);
所有的 roots 被检查和标记为激活(即不是垃圾)。所有的子对象也被递归地检查。从 root 开始的所有对象如果是可达的,它就不被当作垃圾。
所有未被标记的内存会被当做垃圾,收集器现在可以释放内存,归还给操作系统了。

常见的四中内存泄露:
1:意外的全局变量
JavaScript 处理未定义变量的方式比较宽松:未定义的变量会在全局对象创建一个新变量。在浏览器中,全局对象是 window 。

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

真相是:

function foo(arg) {
    window.bar = "this is an explicit global variable";
}

函数 foo 内部忘记使用 var ,意外创建了一个全局变量。此例泄漏了一个简单的字符串,无伤大雅,但是有更糟的情况。
在 JavaScript 文件头部加上 'use strict',可以避免此类错误发生。启用严格模式解析 JavaScript ,避免意外的全局变量

2:被遗忘的计时器或回调函数
在 JavaScript 中使用 setInterval 非常平常。一段常见的代码:

var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

此例说明了什么:与节点或数据关联的计时器不再需要,node 对象可以删除,整个回调函数也不需要了。可是,计时器回调函数仍然没被回收(计时器停止才会被回收)。同时,someResource 如果存储了大量的数据,也是无法被回收的。

对于观察者的例子,一旦它们不再需要(或者关联的对象变成不可达),明确地移除它们非常重要。老的 IE 6 是无法处理循环引用的。如今,即使没有明确移除它们,一旦观察者对象变成不可达,大部分浏览器是可以回收观察者处理函数的。
观察者代码示例:

var element = document.getElementById('button');
function onClick(event) {
    element.innerHTML = 'text';
}
element.addEventListener('click', onClick);

3:DOM 的引用

var elements = {
    button: document.getElementById('button'),
    image: document.getElementById('image'),
    text: document.getElementById('text')
};
function doStuff() {
    image.src = 'http://some.url/image';
    button.click();
    console.log(text.innerHTML);
    // 更多逻辑
}
function removeButton() {
    // 按钮是 body 的后代元素
    document.body.removeChild(document.getElementById('button'));
    // 此时,仍旧存在一个全局的 #button 的引用
    // elements 字典。button 元素仍旧在内存中,不能被 GC 回收。
}

4:闭包

var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  var unused = function () {
    if (originalThing)
      console.log("hi");
  };
  theThing = {
    longStr: new Array(1000000).join('*'),
    someMethod: function () {
      console.log(someMessage);
    }
  };
};
setInterval(replaceThing, 1000);

相同父级闭包,作用域连共享。originalThing在unused作用域链,也在someMethod作用域链。
原文地址https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156
文章中加注释代码,讲的比较清晰

var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  // Define a closure that references originalThing but doesn't ever
  // actually get called. But because this closure exists,
  // originalThing will be in the lexical environment for all
  // closures defined in replaceThing, instead of being optimized
  // out of it. If you remove this function, there is no leak.
  var unused = function () {
    if (originalThing)
      console.log("hi");
  };
  theThing = {
    longStr: new Array(1000000).join('*'),
    // While originalThing is theoretically accessible by this
    // function, it obviously doesn't use it. But because
    // originalThing is part of the lexical environment, someMethod
    // will hold a reference to originalThing, and so even though we
    // are replacing theThing with something that has no effective
    // way to reference the old value of theThing, the old value
    // will never get cleaned up!
    someMethod: function () {}
  };
  // If you add `originalThing = null` here, there is no leak.
};
setInterval(replaceThing, 1000);
1*jkpHoXjLULpVoTFngljaaw.png

我们可以看到str的使用情况
另一篇文章里也有对这个有解释:https://cnodejs.org/topic/5a2794779807389a1809f1af
实际运行

image.png

相关文章

  • JS学习笔记_内存泄露

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

  • js内存泄露

    js内存泄露 js内存的机制 js的基本变量 boolean string number null undefin...

  • Java弱引用学习 WeakHashMap、ReferenceQ

    上一篇文章 Java内存泄露学习 ThreadLocal真的会内存泄露吗 提到ThreadLocal内存泄露的问题...

  • JS内存泄露

    系统进程不再用用到的内存,没有及时释放,就叫做内存泄露(memory leak)。 当内存占用越来越高,轻则影响系...

  • 加载webView 内存泄露 导致内存暴涨的几种解决方案

    转自:iOS_Cloud的博客** 加载webView导致内存泄露的原因是:Html中的js代码会引起内存泄露 *...

  • 内存泄露

    什么是内存泄露 内存泄露:应用程序分配某段内存后,由于设计错误,失去了对某段内存的控制,因此造成了内存的浪费 js...

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

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

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

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

  • js内存泄露总结

    什么是内存泄露 应用程序不再需要占用内存的时候,由于某些原因,内存没有被操作系统或者可用内存池回收。 javasc...

  • JS 内存泄露排查

    在后台在管理界面直接编辑 JS,类是于于下面这些 ${data} 就是动态的数据,到前端之前会做替换。然后每次 a...

网友评论

      本文标题:JS学习笔记_内存泄露

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