摘自:http://bbs.9ria.com/viewthread.php?tid=104161
作者博客:http://www.iamsevent.com/post/3.html
垃圾回收机制:
回收条件:
1:没有其他对象保持对其的引用
2:不存在强引用事件侦听
private var a:Sprite = new Sprite();
this.addChild( a );
a = null;
/*
a不能被回收,因为a被addChild到了this的显示列表中,
因此this就保持着对a的引用,
只清除了变量a对其所实例化的Sprite对象的引用
却没有清除this对其的引用
*/
this.addChild( a );
a = null;
/*
a不能被回收,因为a被addChild到了this的显示列表中,
因此this就保持着对a的引用,
只清除了变量a对其所实例化的Sprite对象的引用
却没有清除this对其的引用
*/
private var a:Sprite = new Sprite();
this.addChild( a );
this.removeChild( a );
a = null;
/*
a能被回收,
因为a所创建的Sprite对象不仅从this的显示列表中移除了,
还释放了a对其的引用,
此时没有任何变量保持着对此Sprite对象的引用了。
*/
this.addChild( a );
this.removeChild( a );
a = null;
/*
a能被回收,
因为a所创建的Sprite对象不仅从this的显示列表中移除了,
还释放了a对其的引用,
此时没有任何变量保持着对此Sprite对象的引用了。
*/
从上面三段代码中我们基本上可以理解第一条原则:
没有其他对象保持着对其的引用的概念了。
但是当你用上数组之后,往往会忽略数组对需要回收的对象的引用,
一起来看接下来几个例子:
private var a:Sprite = new Sprite();
private var arr:Array = [];
arr.push( a );
this.addChild( a );
this.removeChild(a)
a = null;
/*
a不能被回收,
因为数组arr中还保持着对a所实例化的Sprite对象的引用。
为了能够成功地回收a,你还需要将a从数组中剔除:
*/
var index:int = arr.indexOf( a );
arr.splice( index, 1 );
private var arr:Array = [];
arr.push( a );
this.addChild( a );
this.removeChild(a)
a = null;
/*
a不能被回收,
因为数组arr中还保持着对a所实例化的Sprite对象的引用。
为了能够成功地回收a,你还需要将a从数组中剔除:
*/
var index:int = arr.indexOf( a );
arr.splice( index, 1 );
接下来我们看看强引用事件侦听对对象垃圾回收的影响,
若是一个对象存在强引用事件侦听,则其不会被垃圾回收。
看下面的例子:
private var a:Sprite = new Sprite();
this.addChild( a );
a.addEventLitener( MouseEvent.CLICK, onClick );
this.removeChild( a );
a = null;
private function onClick( e:MouseEvent ):void
{
trace("oh, shit!");
}
/*
a不能被回收,因为有一个鼠标点击的侦听器在其身上。
即使你将其从this的显示列表中移去并把a置为了null,
为了顺利回收a,
你需要在把a置为null前移除其所有的事件侦听器。
*/
this.addChild( a );
a.addEventLitener( MouseEvent.CLICK, onClick );
this.removeChild( a );
a = null;
private function onClick( e:MouseEvent ):void
{
trace("oh, shit!");
}
/*
a不能被回收,因为有一个鼠标点击的侦听器在其身上。
即使你将其从this的显示列表中移去并把a置为了null,
为了顺利回收a,
你需要在把a置为null前移除其所有的事件侦听器。
*/
但是,如果你为需要回收的对象添加的事件侦听器为弱引用的话就可以顺利地让对象被回收掉。
如何设置事件侦听器为弱引用?
设置addEventListener方法的最后一个参数为true即可。
需要注意的是,事件侦听器越多越是影响性能,因此对于一些仅使用一次的事件侦听器,及时移除是个很好的习惯。
要清理所有的事件侦听,我有一个比较好的办法,就是每次调用一个对象的addEventListener方法时把添加的事件侦听器记录起来,
日后若要移除全部事件侦听只需要把全部记录着的侦听器遍历一遍,一次移除干净即可:
package
{
import flash.display.Sprite;
public class Test extends Sprite
{
/** 记录所有事件侦听器 */
private var _eventListeners:Object;
public function Test(){}
override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
super.addEventListener(type, listener, useCapture, priority, useWeakReference);
if( !_eventListeners )
_eventListeners = new Object();
//将添加的事件侦听器侦听事件类型以及事件处理函数保存起来
_eventListeners[type] = listener;
}
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
{
super.removeEventListener(type, listener, useCapture);
if( _eventListeners && _eventListeners[type] )
{
delete _eventListeners[type];//删除该侦听器记录
}
}
/** 移除全部事件侦听器 */
public function removeAllEventListener():void
{
for(var event:String in _eventListeners)
{
removeEventListener(event, _eventListeners[event]);
}
}
}
}
{
import flash.display.Sprite;
public class Test extends Sprite
{
/** 记录所有事件侦听器 */
private var _eventListeners:Object;
public function Test(){}
override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
super.addEventListener(type, listener, useCapture, priority, useWeakReference);
if( !_eventListeners )
_eventListeners = new Object();
//将添加的事件侦听器侦听事件类型以及事件处理函数保存起来
_eventListeners[type] = listener;
}
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
{
super.removeEventListener(type, listener, useCapture);
if( _eventListeners && _eventListeners[type] )
{
delete _eventListeners[type];//删除该侦听器记录
}
}
/** 移除全部事件侦听器 */
public function removeAllEventListener():void
{
for(var event:String in _eventListeners)
{
removeEventListener(event, _eventListeners[event]);
}
}
}
}