关于JavaScript的内存泄漏的思考

1. 概念

  1) 内存泄漏就是指程序中不再用到的对象依然占用的内存无法释放;

  2) 程序中的内存过程:系统分配------程序使用 ------ 程序、系统释放

说到内存泄漏不得不提到垃圾回收机制

2. 垃圾回收机制

目前垃圾回收机制有两种:

  1) 引用标记法

    优势:简单

    劣势:对于循环引用的对象无法清除

  2) 标记清除法--解决了循环引用对象

3. 常见的内存泄漏

1)全局变量

  对于定义的全局变量,由于挂在window上,除非刷新浏览器,这个变量就永远不会被回收

2)未销毁的定时器和回调函数

var serverData = loadData();
setInterval(function() {
    var renderer = document.getElementById(‘renderer‘);
    if(renderer) {
        renderer.innerHTML = JSON.stringify(serverData);
    }
}, 5000); // 每 5 秒调用一次

  如果后续renderer元素被移除,此时定时器就没有任何作用,但是如果没有清楚定时器,定时器的内存就没有被回收,这样serverData也无法被回收

3)闭包

  在 JS 开发中, 我们会经常用到闭包, 一个内部函数, 有权访问包含其的外部函数中的变量. 下面这种情况下, 闭包也会造成内存泄露.

var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  var unused = function () {
    if (originalThing) // 对于 ‘originalThing‘的引用
      console.log("hi");
  };
  theThing = {
    longStr: new Array(1000000).join(‘*‘),
    someMethod: function () {
      console.log("message");
    }
  };
};
setInterval(replaceThing, 1000);

  这段代码,每次调用replaceThing时,theThing获得了包含一个巨大的数组和一个对于新闭包someMethod的对象,同时unused是一个引用了originalThing的闭包。

    一旦为同一父作用域中的闭包创建了闭包范围,就会共享作用域。

  这个范例的关键在于,闭包之间是共享作用域,尽管unused可能一直没有被调用,但是someMethod可能会被调用,这样就会导致无法对其进行回收

  修改上述问题:

var theThing = null;
var replaceThing = function(){
  var originalThing = theThing;
  //定义一个引用originalThing但不会
  //实际被调用的闭包。但是因为这个闭包存在,所以
  // originalThing将在词汇环境中用于在replaceThing中定义的所有//闭包,而不是在其中进行优化
  //。如果删除此功能,则无泄漏。
  var unused = function(){
    if(originalThing)
      console.log(“hi”);
  };
  theThing = {
    longStr:new Array(1000000).join(‘*‘),
    //虽然这个
    //函数理论上可以访问originalThing ,但它显然不会使用它。但是因为
    // originalThing是词法环境的一部分,someMethod
    //将保存对originalThing的引用,所以即使我们
    //正在用无效的方式替换theThing
    //引用旧的值ofThing,旧值
    //永远不会被清理干净!
    someMethod:function(){}
  };
  //如果在这里添加`originalThing = null`,则没有泄漏。
};
setInterval(replaceThing,1000);

4)DOM引用

  很多时候,我们对DOM的操作会把DOM的引用保存在一个数组或者Map中

var elements = {
    image: document.getElementById(‘image‘)
};
function doStuff() {
    elements.image.src = ‘http://example.com/image_name.png‘;
}
function removeImage() {
    document.body.removeChild(document.getElementById(‘image‘));
    // 这个时候我们对于 #image 仍然有一个引用, Image 元素, 仍然无法被内存回收.
}

  上述案例中,即使我们对于image元素进行了移除,但是仍然有对image元素的引用,依然无法进行内存回收

  另外需要注意的一个点是, 对于一个 Dom 树的叶子节点的引用. 举个例子: 如果我们引用了一个表格中的 td 元素, 一旦在 Dom 中删除了整个表格, 我们直观的觉得内存回收应该回收除了被引用的 td 外的其他元素. 但是事实上, 这个 td 元素是整个表格的一个子元素, 并保留对于其父元素的引用. 这就会导致对于整个表格, 都无法进行内存回收. 所以我们要小心处理对于 Dom 元素的引用.

参考原文:

https://blog.sessionstack.com/how-javascript-works-memory-management-how-to-handle-4-common-memory-leaks-3f28b94cfbec

https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156

原文地址:https://www.cnblogs.com/KruceCoder/p/10690185.html

时间: 2024-10-29 13:35:59

关于JavaScript的内存泄漏的思考的相关文章

关于Javascript的内存泄漏问题的整理稿

写了好长时间javascript小功能模块,从来没有关注过内存泄漏问题.记得以前写C++程序的时候,内存泄漏是个严重的问题,我想是时候关注一下了.网上找了篇文章,Mark一下.原文地址:http://www.blogjava.net/tim-wu/archive/2006/05/29/48729.html 常规循环引用内存泄漏和Closure内存泄漏 要了解javascript的内存泄漏问题,首先要了解的就是javascript的GC原理. 我记得原来在犀牛书<JavaScript: The D

Javascript的内存泄漏分析

作为程序员(更高大尚的称谓:研软件研发)的我们,无论是用Javascript,还是.net, java语言,肯定都遇到过内存泄漏的问题.只不过他们都有GC机制来帮助程序员完成内存回收的事情,如果你是C++开发者(你懂的).....,如果你是前端开发者,肯定在使用Javascript(你或者会说,Js是世界上最棒的语言),但我这里也得告诉你,Js的内存泄漏会来得更为突然,或者让你都无法察觉.本文就带大家领略一下Js的风骚: 一.模块化引起的内存泄漏 代码如下: // module date.js

JavaScript 中的内存泄漏

JavaScript 是一种垃圾收集式语言,这就是说,内存是根据对象的创建分配给该对象的,并会在没有对该对象的引用时由浏览器收回.JavaScript 的垃圾收集机制本身并没有问题,但浏览器在为 DOM 对象分配和恢复内存的方式上却有些出入. Internet Explorer 和 Mozilla Firefox 均使用引用计数来为 DOM 对象处理内存.在引用计数系统,每个所引用的对象都会保留一个计数,以获悉有多少对象正在引用它.如果计数为零,该对象就会被销毁,其占用的内存也会返回 给堆.虽然

JavaScript的闭包和内存泄漏问题

闭包 JavaScript中必须提到的功能最强大的抽象概念之一:闭包.它究竟是做什么的呢? 1 function makeAdder(a) { 2 return function(b) { 3 return a + b; 4 } 5 } 6 var x = makeAdder(5); 7 var y = makeAdder(20); 8 x(6); // 11 9 y(7); // 27 makeAdder这个名字本身应该能说明函数是用来做什么的:他创建了一个新的adder函数,这个函数自身带有

javaScript内存泄漏

first: 先理解我们的基本概念,什么是内存泄漏: 答: 不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak) 程序的运行需要内存.只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存. 对于持续运行的服务进程(daemon),必须及时释放不再用到的内存.否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分

了解 JavaScript 应用程序中的内存泄漏

简介 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分配和释放的具体细节. 许多功能无需考虑内存管理即可实现,但却忽略了它可能在程序中带来重大的问题.不当清理的对象可能会存在比预期要长得多的时间.这些对象继续响应事件和消耗资源.它们可强制浏览器从一个虚拟磁盘驱动器分配内存页,这显著影响了计算机的速度(在极端的情形中,会导致浏览器崩溃). 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在.在最近几

javascript 内存泄漏的学习

概念 内存泄漏: 用动态存储分配函数动态开辟的空间,在使用完毕后未释放, 木有任何指针指向他,结果导致一直占据该内存单元.直到程序结束.(其实说白了就是该内存空间使用完毕之后未回收, 占着茅坑不**)即所谓内存泄漏. 等所有内存都被占完之后, 系统就跪了. 内存分配方式 说道内存泄露,就不得不谈到内存分配的方式.内存分配有三种方式,分别是: 一.静态分配( Static Allocation ):静态变量和全局变量的分配形式.如果把房间看做一个程序,我们可以把静态分配的内存当成是房间里的耐用家具

前端开发中javascript闭包会引发内存泄漏么?

本文主要是和大家一起来讨论下javascript的闭包会造成内存泄漏吗?希望通过本文的分享对大家学习javascript有所帮助.  在谈内存泄漏这个问题之前先看看JavaScript的垃圾收集机制,JavaScript 具有自动垃圾收集机制,就是找出那些不再继续使用的变量,然后释放其占用的内存.为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间).常用的的方法有两种,即标记清楚和引用计数.  标记清除  JavaScript 中最常用的垃圾收集方式是标记清除(mark-and-s

关于JavaScript内存泄漏的质疑

近几天看了些关于JavaScript内存管理的文章,相对于Java JVM的内存管理,显得简单些. 在学习的过程中,发现有不少网友谈到了循环引用,说循环引用会造成内存泄漏,垃圾回收器无法回收. 实际上,并没有这么可怕,根据小菜目前的了解,这种循环引用造成的内存泄漏,仅仅会发生在低版本的IE浏览器上,现代浏览器是不会这么蠢的. 举个例子,网络上流行的说法大致有如下两种: 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta char