Js的垃圾回收机制案例

简介

基础数据是存储在栈中的,如number,string,而对象数据是存储在堆中,通过栈内一个指针指向堆内存中

var a = b = {},其实只会分配一个对象的内存

而这个对象一旦不使用了,就需要被释放

回收原理

var a = b = {};

这个对象引用计数为2,一旦 a = b = null,这时候这个对象再也无法访问到了,就被垃圾回收了

复合引用

同样 var a = {b: {}},会创建两个对象,但是一旦 a = null,内部b的那个对象也无法访问到了,进而被回收了

egret的案例

在egret官网会看到很多例子
this.addEventListener(egret.Event.REMOVE_FROM_STAGE, this.dispose, this);

用来做一个销毁的钩子函数,我们不禁想:(这个事件本身不需释放吗?)

参考事件的机制,实际上事件就是给把所有callback给注册到数组里面,但是这个数组还是当前的this,因为显示对象默认继承 egret.EventDispatcher,当前this的对象访问不到,这数组的自然也访问不到了

不过不太建议使用这个方法,因为有时候我们仅仅setChildIndex也会触发此方法,应该有一个统一的destroy的钩子,外部驱动

因此内部事件通常不需要考虑释放,外部事件需要,因为外部事件需要劫持当前对象的this,如外部EventCenter的监听

Promise的案例

Promise通常用于一些异步的场景,代表在一定时间之后,会触发的一些行为的对象,但是如果中途clearTimeout等终止操作,是否导致一直pending是否内存泄漏呢?

经过测试,其实Promise内部的异步处理逻辑通常都是外部驱动的,如setTimeout,此时会把闭包内的resolve方法传递给了外部驱动的队列中,外部持有闭包内的对象,导致拥有这个域的Promise对象不会被回收(尽管我们不需保存promise的引用),一旦我们手动clearTimeout,Promise内部变量不再被外部劫持,虽然无法resolve,但也会被自动回收了

常见的情形是我们会存在多分支干扰的情形,如游戏流程会有一个总的timeout计时器,如果我们在await一个开场动画之后需要生成棋盘,但是此时timeout,其实我们可以stop开场动画,同时这个promise还会被回收,即await不一定一定需要reject来改变流程,流程是可中断的

内存泄漏排查

  • 我们可以通过 chrome 的 Memory 做一些比对,查看堆内存中对象的增量来判定
  • 经过测试,我们甚至可以查看一个对象的引用关系!也许我们能够进一步访问[[scope]]那些私有化的变量?
  • 通常而言,平时开发我们泄漏点主要在数组,因为一个对象属性最多一次只会劫持一个obj的引用,但是数组可以无限劫持!如龙骨的世界钟数组,事件中心的callback数组,缓动,定时器的全局驱动数组
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容