博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
垃圾回收与内存泄漏
阅读量:6772 次
发布时间:2019-06-26

本文共 2825 字,大约阅读时间需要 9 分钟。

原文地址:

垃圾回收--引用计数

将资源的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。

会导致更多的内存泄漏,已不被采用。

导致的特殊内存泄漏

循环引用导致内存不能正常被回收

// 函数 a 执行完后,本来 x, y 对象都应该在垃圾回收阶段被回收, 可是由于存在循环引用,也不能被回收。function a () {    var x = {};    var y = {};    x.z = y;    y.z = x;}a();

IE 6, 7 对DOM对象进行引用计数回收,这样简单的垃圾回收机制,非常容易出现循环引用问题导致内存不能被回收, 进行导致内存泄露等问题。

!function(){    // IE 6, 7 中下列代码会导致 btn 不能被回收    var btn = document.getElementsByTagName('button');    btn.onclick = function(){        console.log(btn.innerHTML);    };}();

垃圾回收--标记清除

标记清除的方式需要对程序的对象进行两次扫描,第一次从根(Root)开始扫描,被根引用了的对象标记为不是垃圾,不是垃圾的对象引用的对象同样标记为不是垃圾,以此递归。所有不是垃圾的对象的引用都扫描完了之后。就进行第二次扫描,第一次扫描中没有得到标记的对象就是垃圾了,对此进行回收。

大多数浏览器采用此回收机制。

内存泄漏

意外的全局变量

function foo(arg) {    // 没有 var 时,默认全局    bar = {};}

偶然创建全局变量

function foo() {    this.bar = {};}// 此时执行 foo 函数,this 其实是指代 windowfoo();

没有及时清除的定时器和回调函数

// 未清除定时器!function(){    var node = document.getElementById('search');    setInterval(function() {        console.log(node);        if(node) {            node.innerHTML = new Date();        }    }, 1000);    // 移除node节点    node.remove();}();// 未清除回调函数!function(){    var element = document.getElementById('button');    function onClick(event) {        element.innerHtml = 'text';    }    element.addEventListener('click', onClick);    // 在 IE6、IE7 浏览器上,移除 node 之前需要手动的 removeEventListener,这样才能保证 element 被正常回收(其实就是循环引用)    element.removeEventListener('click', onClick);    element.parentNode.removeChild(element);}();

DOM之外的引用

var app = document.getElementById('app');var son = document.getElementById('son');app.remove(); // 移除 app 节点app = null; // 释放 app 引用console.log(son.parentNode); // app 可访问,son 在全局的引用,导致 app 的 dom 没有被释放

闭包被外部引用

var replaceThing = function () {      // 为了方便观察内存情况,创建了一个很大的字符串,这样数组本身会占用很大的内存      var originalThing = new Array(100000000).join('*');      var outer = 'outer str';      console.log('new...');      return function () {        if (originalThing)          console.log(outer);      };    };// 由于生成的函数被 closureFn 引用,所以内存不释放var closureFn = replaceThing();closureFn();// 使用以下方式可以得到释放replaceThing()();

多重闭包

var theThing = null;var replaceThing = function () {  var originalThing = theThing;  var unused = function () {    if (originalThing)      console.log('hi');  };  theThing = {    // 为了方便观察内存情况,创建了一个很大的字符串,这样数组本身会占用很大的内存    longStr: new Array(100000000).join('*'),    someMethod: function () {      console.log('123');    }  };};// 每1秒执行一次,看内存变化setInterval(replaceThing, 1000);// 由于 unused 和 theThing.someMethod 在一个闭包内,导致共享一个闭包作用域,从而关联两个函数,但是不会造成对 originalThing 的关联。originalThing 的关联是由 unused 内部引用导致的。由此可见 replaceThing 内部的变量都被紧密联系在一起。

如何避免内存泄漏

  • 尽量避免使用全局变量,例如使用立即执行函数的形式。
  • 使用“严格模式”开发,避免因为我们的疏忽导致意外产生全局变量。
  • 对于一些占用内存较大的对象,在变量不在使用后,手动将其赋值为 null,例如前面例子中的超大的数组。
  • 尽量避免把闭包内部与外部产生关联引用,例如上面例子中的 theThing 变量

转载于:https://www.cnblogs.com/xingkongbj/p/9237650.html

你可能感兴趣的文章
HDU1874畅通工程续(floyd||dijkstra)
查看>>
数据分析--布林带策略(择时)
查看>>
二十年后的回眸(6)——中途夭折的初次创业
查看>>
DB2日常运维之总结
查看>>
用hadoop中的libhdfs和fuse-dfs构建快速云存储
查看>>
Redis实战(6)数据类型四Sets
查看>>
Android Studio第八期 - 自定义布局无网有网状态
查看>>
读《Go并发编程实战》第4章 流程控制方式
查看>>
IT168:数据库安全审计用户需求调查报告
查看>>
Lync Server 2010不同规模拓扑图详解
查看>>
验证控件收藏
查看>>
安装配置Varnish3.0手记
查看>>
舌尖上的职场(三)我来买单!
查看>>
HighChartS cpu利用率动态图(Java版)
查看>>
让人头疼的关键用户
查看>>
DBMS_REPAIR example
查看>>
初识linux
查看>>
ORA-07445 [SIGBUS] [Object specific hardware error]错误一例
查看>>
Yii2的Html,Request组件详解
查看>>
使用ASP.NET实现Windows Service定时执行任务
查看>>