内存管理及分析

转自以下链接:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Memory_Management

https://zhuanlan.zhihu.com/p/30552148

https://juejin.im/post/5cbae494f265da03502b36b3

JavaScript创建变量(对象,字符串等)时分配内存,并且在不再使用它们时“自动”释放。 后一个过程称为垃圾回收。这个“自动”是混乱的根源,并让JavaScript开发者感觉他们可以不关心内存管理。

一、内存回收策略

通常情况下有两种内存管理实现方式:标记清除引用计数。引用计数不太常用,标记清除较为常用。

引用计数有循环引用的限制,从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。

二、GC

1、基础方案

Javascript引擎基础GC方案是(simple GC):mark and sweep(标记清除),即:

遍历所有可访问的对象。

回收已不可访问的对象。

2、什么时候触发 GC

垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。IE6的垃圾回收是根据内存分配量运行的,当环境中存在256个变量、4096个对象、64k的字符串任意一种情况的时候就会触发垃圾回收器工作,看起来很科学,不用按一段时间就调用一次,有时候会没必要,这样按需调用不是很好吗?但是如果环境中就是有这么多变量等一直存在,现在脚本如此复杂,很正常,那么结果就是垃圾回收器一直在工作,这样浏览器就没法儿玩儿了。

微软在IE7中做了调整,触发条件不再是固定的,而是动态修改的,初始值和IE6相同,如果垃圾回收器回收的内存分配量低于程序占用内存的15%,说明大部分内存不可被回收,设的垃圾回收触发条件过于敏感,这时候把临街条件翻倍,如果回收的内存高于85%,说明大部分内存早就该清理了,这时候把触发条件置回。这样就使垃圾回收工作职能了很多

3、GC的缺陷

javascript的GC策略也无法避免一个问题:GC时,停止响应其他操作,这是为了安全考虑。而Javascript的GC在100ms甚至以上,对一般的应用还好,但对于JS游戏,动画对连贯性要求比较高的应用,就麻烦了。这就是新引擎需要优化的点:避免GC造成的长时间停止响应。

4、优化策略

分代回收(Generation GC)这个和Java回收策略思想是一致的,也是V8所主要采用的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时。如图:


这里需要补充的是:对于tenured generation对象,有额外的开销:把它从young generation迁移到tenured generation,另外,如果被引用了,那引用的指向也需要修改。这里主要内容可以参考深入浅出Node中关于内存的介绍,很详细~

增量GC这个方案的思想很简单,就是“每次处理一点,下次再处理一点,如此类推”。如图:


这种方案,虽然耗时短,但中断较多,带来了上下文切换频繁的问题。

因为每种方案都其适用场景和缺点,因此在实际应用中,会根据实际情况选择方案。

比如:低 (对象/s) 比率时,中断执行GC的频率,simple GC更低些;如果大量对象都是长期“存活”,则分代处理优势也不大。


五、常见内存泄漏原因

1、过多不必要全局变量

2、未销毁的定时器和回调函数 (如果不是在全局,新的垃圾清除机制还有这个问题么???)

3、闭包?


4、dom 引用

image = document.getElementById('image')

如果我们移除了dom 元素,但是由于一些原因 image 变量一直存在的话, dom 节点依然被保存在内存中,如果很大,会是很大的内存损失。

你可能感兴趣的:(内存管理及分析)