垃圾回收机制

浏览器的 Javascript 具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存。其原理是:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大并且GC时停止响应其他操作,所以垃圾回收器会按照固定的时间间隔周期性的执行。

只有函数内的变量才可能被回收

不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量,全局变量的生命周期直至浏览器卸载页面才会结束。局部变量只在函数的执行过程中存在,而在这个过程中会为局部变量在栈或堆上分配相应的空间,以存储它们的值,然后在函数中使用这些变量,直至函数结束,而闭包中由于内部函数的原因,外部函数并不能算是结束。

代码说明:

function fn1() {var obj = {name: 'hanzichi', age: 10};
}
function fn2() {var obj = {name:'hanzichi', age: 10};return obj;
}var a = fn1();
var b = fn2();

分析:
我们来看代码是如何执行的。首先声明了两个函数,分别叫做 fn1 和 fn2,当 fn1 被调用时,进入 fn1 的环境,会开辟一块内存存放对象{name: 'hanzichi', age: 10},而当调用结束后,出了fn1的环境,那么该块内存会被 JS 引擎中的垃圾回收器自动释放;在 fn2 被调用的过程中,返回的对象被全局变量 b 所指向,所以该块内存并不会被释放。

到底哪个变量是没有用的?

垃圾收集器必须跟踪到底哪个变量没用,对于不再有用的变量打上标记,以备将来收回其内存。通常情况下有两种实现方式:标记清除和引用计数。引用计数不太常用,标记清除较为常用。

标记清除 (常用)

js中最常用的垃圾回收方式就是标记清除。当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。
从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。
而当变量离开环境时,则将其标记为“离开环境”。
function test(){var a = 10 ;       // 被标记 ,进入环境
var b = 20 ;       // 被标记 ,进入环境
}
test();            // 执行完毕 之后 a、b又被标离开环境,被回收。

垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾回收器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
到目前为止,IE9+、Firefox、Opera、Chrome、Safari 的 JS 实现使用的都是标记清除的垃圾回收策略,只不过垃圾收集的时间间隔互不相同。

引用计数

引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。
如果同一个值又被赋给另一个变量,则该值的引用次数加 1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。
当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。
这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为 0 的值所占用的内存。
function test() {var a = {};    // a指向对象的引用次数为1var b = a;     // a指向对象的引用次数加1,为2var c = a;     // a指向对象的引用次数再加1,为3var b = {};    // a指向对象的引用次数减1,为2
}

什么是内存泄漏?

程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。

对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。

不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。

Chrome 浏览器查看内存泄漏

如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。这就要求实时查看内存占用。

Chrome自带的内存调试工具可以很方便地查看内存使用情况和内存泄露:
在 Timeline -> Memory 点击record即可:

  • 打开开发者工具,选择 Timeline 面板
  • 在顶部的Capture字段里面勾选 Memory
  • 点击左上角的录制按钮。
  • 在页面上进行各种操作,模拟用户的使用情况。
  • 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。

Vue 中的内存泄漏问题

  1. 如果在mounted/created钩子中使用 JS 绑定了DOM/BOM对象中的事件,需要在 beforeDestroy中做对应解绑处理;
  2. 如果在 mounted/created钩子中使用了第三方库初始化,需要在 beforeDestroy中做对应销毁处理(一般用不到,因为很多时候都是直接全局 Vue.use);
  3. 如果组件中使用了 setInterval,需要在 beforeDestroy中做对应销毁处理;
mounted() {const box = document.getElementById('time-line')this.width = box.offsetWidththis.resizefun = () => {this.width = box.offsetWidth}window.addEventListener('resize', this.resizefun)},beforeDestroy() {window.removeEventListener('resize', this.resizefun)this.resizefun = null}

js中的内存泄漏

1. 循环引用

一个很简单的例子:一个DOM对象被一个Javascript对象引用,与此同时又引用同一个或其它的Javascript对象,这个DOM对象可能会引发内存泄露。这个DOM对象的引用将不会在脚本停止的时候被垃圾回收器回收。要想破坏循环引用,引用DOM元素的对象或DOM对象的引用需要被赋值为null。

2. 闭包

在闭包中引入闭包外部的变量时,当闭包结束时此对象无法被垃圾回收(GC)。

var a = function() {var largeStr = new Array(1000000).join('x');return function() {return largeStr;}
}();

3. DOM泄露
当原有的COM被移除时,子结点引用没有被移除则无法回收。

var select = document.querySelector;
var treeRef = select('#tree');//在COM树中leafRef是treeFre的一个子结点
var leafRef = select('#leaf');
var body = select('body');body.removeChild(treeRef);//#tree不能被回收入,因为treeRef还在
//解决方法:
treeRef = null;//tree还不能被回收,因为叶子结果leafRef还在
leafRef = null;//现在#tree可以被释放了。

4. Timers计(定)时器泄露

定时器也是常见产生内存泄露的地方

for (var i = 0; i < 90000; i++) {var buggyObject = {callAgain: function() {var ref = this;var val = setTimeout(function() {ref.callAgain();}, 90000);}}buggyObject.callAgain();//虽然你想回收但是timer还在buggyObject = null;
}

js的垃圾回收和内存泄露相关推荐

  1. 闭包,作用域链,垃圾回收,内存泄露

    关于闭包,我翻了几遍书,看了几遍视频,查了一些资料,可是还是迷迷糊糊的,干脆自己动手来个总结吧 !欢迎指正... (- o -)~zZ 1. 什么是闭包? 来看一些关于闭包的定义: 闭包是指有权访问另 ...

  2. JavaScript 的垃圾回收与内存泄露

    2019独角兽企业重金招聘Python工程师标准>>> JavaScript采用垃圾自动回收机制,运行时环境会自动清理不再使用的内存,因此javascript无需像C++等语言一样手 ...

  3. flash垃圾回收和内存泄露

    GC的原子模型 之所以用"原子模型"(Atomic Model)这个词,是因为这篇文章是用来描述GC怎么样在 player中工作的模型,但是不包涵其相关的技术实现或细节描述. 之所 ...

  4. Python垃圾回收与内存泄露

    Python是面向对象.高级编程语言,其世界里万物皆对象,当我们编写的程序运行时,代码中定义的对象在物理内存中会占用相应的空间.现在流行的高级语言如Java,C#等都采用了垃圾收集机制自动管理内存使用 ...

  5. JavaScript 中的垃圾回收和内存泄露如何处理?| 技术头条

    作者 | 浪里行舟 责编 | 郭芮 程序的运行需要内存.只要程序提出要求,操作系统或者运行时就必须供给内存.所谓的内存泄漏简单来说是不再用到的内存,没有及时释放.为了更好避免内存泄漏,我们先介绍Jav ...

  6. 【转】JavaScript 中的垃圾回收和内存泄露如何处理

    转自 https://blog.csdn.net/csdnnews/article/details/89596750?ops_request_misc=%257B%2522request%255Fid ...

  7. js内存泄露 垃圾回收_Java内存体系结构(模型),垃圾回收和内存泄漏

    js内存泄露 垃圾回收 Java内存架构(Java内存模型) 上面是堆的Java内存模型以及Java虚拟机(JVM)中运行的任何Java应用程序的PermGen. 还提供了比率,以使您更好地了解如何在 ...

  8. .NET深入学习笔记(3):垃圾回收与内存管理

    今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...

  9. 深入了解C#系列:谈谈C#中垃圾回收与内存管理机制

    今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...

最新文章

  1. 时代亿信 文件共享访问控制网关
  2. GraphQL入门之GraphQL查询的规范
  3. JDK9的新特性:JPMS模块化
  4. .Net 中的序列化与反序列化 (转)
  5. linux装nvidia驱动没有图形界面,[转]Fedora 13下安装Nvidia显卡驱动的方法/Linux无法进入X Windows 图形界面的解决方法...
  6. java将csv导入hdfs_把HDFS里的json数据转换成csv格式
  7. crtmpserver 配置说明_crtmpserver框架代码详解
  8. 多学一点(十二)——使用extundelete恢复Linux下误删除文件
  9. linux shell脚本字符串 字段分隔符 存入数组 根据下标取值
  10. 真心推荐8个高质量Java学习网站,一起从入门到精通java语言,大厂java面试真题分享,建议码住!
  11. 经典 55道 MySQL面试题及答案
  12. python微信语音转发方法_微信语音转发最方便的方法,我现在才知道
  13. 教你成为质量管理高手GJB
  14. Photoshop CC 2018安装破解
  15. freyja框架 github地址
  16. LTM系统并联接入方式数据包交互分析
  17. 普林斯顿算法课Part2第四周作业_Boggle
  18. linux cadaver 命令,对于linux中线程id的讨论
  19. 计算机有效教学案例分析,中职计算机应用基础有效教学案例分析.doc
  20. Qt几个月的学习心得及展望

热门文章

  1. 绘图机写单线字,实验报告不用自己写啦
  2. VsCode 提示 import “XXX模块” could not be resolved问题解决
  3. C++ 面试宝典 - 知识点集锦
  4. Vue textarea 和input 开发ios点击空白地方键盘不收起问题
  5. ubuntu系统:插入耳机,两只耳机有一只没有声音或者声音偏小的问题
  6. poco新增对cocos c++项目的支持~
  7. 详解redis的三种特殊数据类型
  8. Android 项目工程优化
  9. scp指令,进行服务器之间数据传输
  10. The type org.springframework.dao.DataAccessException cannot be resolved. It is indirectly referenced