博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
As3中强引用和弱引用比较
阅读量:4106 次
发布时间:2019-05-25

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

弱引用英文叫做weak reference,与之相反的是强引用(strong reference)。引用不是对象本身,而是类似于指向对象的一个指针。通常都说当至少还存在一个引用指向某个对象的时候,这个对象就不会被gc,这里所说的引用就是强引用,而不是弱引用。反过来说,即使有N多弱引用指向某个对象,而没有一个强引用指向该对象时,这个对象也会被gc,当gc发生后,所有的弱引用指向的对象就不存在了。这就是强引用与弱引用的本质区别。

AS3中常用到弱引用的地方有addEventListener方法和Dictionary类。
addEventListener方法的参数表为addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false)。其中第5个参数表示是否使用弱引用。也就是说当useWeakReference=false时,EventDispatcher.addEventListener就会在EventDispatcher对象中添加一个对listener这个函数对象的强引用;而当useWeakReference=true时,EventDispatcher.addEventListener方法在EventDispatcher对象中添加的是对listener的弱引用,此时如果这个listener函数对象只是作为EventDispatcher对象的征听器被引用时,那么gc执行时就会回收这个listener函数,从而EventDispatcher对象的这个征听器就不存在了。用简单的代码来证明一下:

[javascript]
  1. var sp:Sprite = new Sprite();  
  2. var eventHandler:Function = function(e:Event){ trace(“event fired”); };  
  3. //添加弱引用   
  4. sp.addEventListener(Event.ENTER_FRAME,eventHandler,false,0,true);  
  5. //取消eventHandler对函数的引用   
  6. eventHandler = null;  
  7. //强制进行gc,此函数只能在debug版的fp中才有效   
  8. System.gc();  
  9. /* 
  10. 运行结果:因为sp.addEventListener中添加的是对eventHandler函数的弱引用,当唯一指向函数的强引用eventHandler变成null以后,这个征听器函数就会被gc。不过gc不是立即发生,因此要强制进行gc后才能看到在输出窗口中不会有event fired输出。如果在sp.addEventListener使用强引用,那么当eventHandler变成null以后,即使进行强制gc,还是会不断输出event fired。因为征听器函数还作为sp的一个征听器被引用,而且是强引用,因此就不会被gc。 
  11. */  
var sp:Sprite = new Sprite();var eventHandler:Function = function(e:Event){ trace(“event fired”); };//添加弱引用sp.addEventListener(Event.ENTER_FRAME,eventHandler,false,0,true);//取消eventHandler对函数的引用eventHandler = null;//强制进行gc,此函数只能在debug版的fp中才有效System.gc();/*运行结果:因为sp.addEventListener中添加的是对eventHandler函数的弱引用,当唯一指向函数的强引用eventHandler变成null以后,这个征听器函数就会被gc。不过gc不是立即发生,因此要强制进行gc后才能看到在输出窗口中不会有event fired输出。如果在sp.addEventListener使用强引用,那么当eventHandler变成null以后,即使进行强制gc,还是会不断输出event fired。因为征听器函数还作为sp的一个征听器被引用,而且是强引用,因此就不会被gc。*/

上面的例子留下来了一个问题:如果sp.addEventListerner添加的是强引用,当指向征听器函数的eventHandler设为空后,这个征听器函数仍然不会被gc,那么怎样才能让它被gc掉呢?答案很显然,也就是当sp被gc掉以后,那么这个征听器函数也会被gc掉,因为sp指向的对象中保留了对征听器的唯一强引用。sp怎么才能被gc掉?从AS2走过来的人往往都容易想到removeChild方法。但是AS3中的removeChild方法作用只是把一个DisplayObject对象从Display List中删除,同时也删除Display List中所存在的对这个DisplayObject对象的引用。但是如果这个DisplayObject对象还被其它变量引用时,它就不会被gc。所以说removeChild是必须的,但不足够,还需要删除Display List之外的所有引用才行!当然如果这个DisplayObject不在Display List中的话,就没有必要removeChild。下面也用一个例子说明一下:

[javascript]
  1. var sp1:Sprite = new Sprite();  
  2. var sp2:Sprite = new Sprite();  
  3. var eventHandler:Function = function(e:Event){trace(“event fired”);};  
  4. //sp1添加对eventHandler的强引用   
  5. sp1.addEventListener(Event.ENTER_FRAME,eventHandler);  
  6. //sp2添加对eventHandler的弱引用,用于查看sp1被gc后征听器是否也被gc   
  7. sp2.addEventListener(Event.ENTER_FRAME,eventHandler,false,0,true);  
  8. //取消eventHandler对函数的引用   
  9. eventHandler = null;  
  10. //取消sp1对Sprite对象的引用使其可以被gc,因为Sprite对象没有添加到Display List中,所以不需要removeChild。   
  11. sp1 = null;  
  12. //强制进行gc,此函数只能在debug版的fp中使用   
  13. System.gc();  
  14. /* 
  15. 运行结果:当取消eventHandler对函数的引用后,对函数唯一的强引用就只存在与sp1所引用的Sprite对象中,当sp1不再引用Sprite对象时,这个Sprite对象就会被gc,因此对征听器函数的唯一强引用也没了,剩下sp2中对函数的引用是弱引用,因此强制gc后,sp2的征听器就没了,所以就不会看到输出event fired。同样的如果取消sp1对Sprite对象的引用,而是使用sp1的removeEventListerner方法取消对征听器函数的引用,征听器函数也会被gc,而sp1引用的Sprite对象还存在。 
  16. */  
var sp1:Sprite = new Sprite();var sp2:Sprite = new Sprite();var eventHandler:Function = function(e:Event){trace(“event fired”);};//sp1添加对eventHandler的强引用sp1.addEventListener(Event.ENTER_FRAME,eventHandler);//sp2添加对eventHandler的弱引用,用于查看sp1被gc后征听器是否也被gcsp2.addEventListener(Event.ENTER_FRAME,eventHandler,false,0,true);//取消eventHandler对函数的引用eventHandler = null;//取消sp1对Sprite对象的引用使其可以被gc,因为Sprite对象没有添加到Display List中,所以不需要removeChild。sp1 = null;//强制进行gc,此函数只能在debug版的fp中使用System.gc();/*运行结果:当取消eventHandler对函数的引用后,对函数唯一的强引用就只存在与sp1所引用的Sprite对象中,当sp1不再引用Sprite对象时,这个Sprite对象就会被gc,因此对征听器函数的唯一强引用也没了,剩下sp2中对函数的引用是弱引用,因此强制gc后,sp2的征听器就没了,所以就不会看到输出event fired。同样的如果取消sp1对Sprite对象的引用,而是使用sp1的removeEventListerner方法取消对征听器函数的引用,征听器函数也会被gc,而sp1引用的Sprite对象还存在。*/

Dictionary的弱引用与addEventListener的原理相同,只不过Dictionary的弱引用指的是对key的弱引用,而不是对value的弱引用。实际上Dictionary对象中保留的是对value的强引用,而且就算value对应的key对象已经被gc了,Dictionary对象中对value的强引用还存在,而且还造成一个不好的影响,就是key被gc后,就无法删除Dictionary对象中对value的强引用。因此我觉得在使用Dictionary对象的时候,如果要删除key的话,应首先delete Dictionary对象中对value的强引用。

[javascript]
  1. //true表示使用弱引用   
  2. var dic:Dictionary = new Dictionary(true);  
  3. //建立key和value,之所以把key和value都定为函数,是为了检查其是否被gc掉   
  4. var key:Function = function (e:Event){trace(“key is alive”);};  
  5. var value:Function = function (e:Event){trace(“value is alive”);};  
  6. //把key和value都加为弱引用的征听器,不影响它们被gc   
  7. addEventListener(Event.ENTER_FRAME,key,false,0,true);  
  8. addEventListener(Event.ENTER_FRAME,value,false,0,true);  
  9. //取消value引用,取消后函数唯一的强引用就存在dic中   
  10. value = null;  
  11. /*取消key引用,dic使用弱引用,因此函数会被gc。再此如果不删除dic中对value的引用,以后就没机会删除了。删除对value的引用可使用delete dic[key];*/  
  12. key = null;  
  13. //强制gc   
  14. System.gc();  
  15. /* 
  16. 运行结果:当取消key对函数的引用后,函数就会被gc。而取消value引用后,在dic中还存在对函数的强引用,因此key对应的征听器不输出了,而value对应的征听器还在输出。而且在取消key引用之前没有删除dic对value的强引用,那么之后只能通过gc掉dic才能使value对应的函数被gc。 
  17. */  
//true表示使用弱引用var dic:Dictionary = new Dictionary(true);//建立key和value,之所以把key和value都定为函数,是为了检查其是否被gc掉var key:Function = function (e:Event){trace(“key is alive”);};var value:Function = function (e:Event){trace(“value is alive”);};//把key和value都加为弱引用的征听器,不影响它们被gcaddEventListener(Event.ENTER_FRAME,key,false,0,true);addEventListener(Event.ENTER_FRAME,value,false,0,true);//取消value引用,取消后函数唯一的强引用就存在dic中value = null;/*取消key引用,dic使用弱引用,因此函数会被gc。再此如果不删除dic中对value的引用,以后就没机会删除了。删除对value的引用可使用delete dic[key];*/key = null;//强制gcSystem.gc();/*运行结果:当取消key对函数的引用后,函数就会被gc。而取消value引用后,在dic中还存在对函数的强引用,因此key对应的征听器不输出了,而value对应的征听器还在输出。而且在取消key引用之前没有删除dic对value的强引用,那么之后只能通过gc掉dic才能使value对应的函数被gc。*/

 

转载地址:http://hrjsi.baihongyu.com/

你可能感兴趣的文章
7 年工作经验,面试官竟然还让我写算法题???
查看>>
被 Zoom 逼疯的歪果仁,造出了视频会议机器人,同事已笑疯丨开源
查看>>
再见,Eclipse...
查看>>
如果你还不了解 RTC,那我强烈建议你看看这个!
查看>>
沙雕程序员在无聊的时候,都搞出了哪些好玩的小玩意...
查看>>
漫话:为什么你下载小电影的时候进度总是卡在 99% 就不动了?
查看>>
我去!原来大神都是这样玩转「多线程与高并发」的...
查看>>
当你无聊时,可以玩玩 GitHub 上这个开源项目...
查看>>
B 站爆红的数学视频,竟是用这个 Python 开源项目做的!
查看>>
安利 10 个让你爽到爆的 IDEA 必备插件!
查看>>
自学编程的八大误区!克服它!
查看>>
GitHub 上的一个开源项目,可快速生成一款属于自己的手写字体!
查看>>
早知道这些免费 API,我就可以不用到处爬数据了!
查看>>
Java各种集合类的合并(数组、List、Set、Map)
查看>>
Mysql复制表以及复制数据库
查看>>
进程管理(一)
查看>>
linux 内核—进程的地址空间(1)
查看>>
存储器管理(二)
查看>>
开局一张图,学一学项目管理神器Maven!
查看>>
Android中的Binder(二)
查看>>