October 14, 2007

[as hack技术]垃圾回收机强制执行

ActionScript3天地会公测中...

哈哈,Moonspirite兄弟发的一篇好文,转载来跟大家分享。我稍稍做了一点调整。期待Moonspirite再出好文,呵呵。
保留原文出处链接和原帖的讨论:[as hack技术]垃圾回收机强制执行
原文如下:

----------------------------------------------------------------------------------------
首先,要感谢校友学长“费gg”的帮助,提供了核心的hack技术的方法。
然后鉴于几天前一网友关于画上万个sprite之后内存增大问题,在此一并作一下讨论和解决。
-----------------------------------------------------------------------------------------
概述:AVM2理论上是自带垃圾回收机的,但是具体何时进行垃圾回收,理论上非人为所能控制,而我们若要强制启用垃圾回收机,则需要用一些非正规手段,比如如下会提到的手段。

关键字:垃圾回收

核心hack技术
批注:所谓强制执行垃圾回收机,是指通过故意使swf在运行时出错,然后throw出错误,而同时通过catch error来继续运行swf文件。而垃圾回收机则会在swf抛出错误的时候,被强制执行一次,以清除内存中无效的数据占用,减少资源的消耗。
我当初也是这么理解的,不过从“费gg”处所学到的,包括自己所测试的,并不是所有的error throw都能触发垃圾回收机,而也只局限于某些特定的error,而上文的例子中的这一error恰为其中的一种error类型。


try{
new LocalConnection().connect("MoonSpirit");
new LocalConnection().connect("MoonSpirit");
}catch(error : Error){

}


运行上述代码,可强制执行一次垃圾回收机。

具体测试:

分别用initNoBitmapDataView()和initBitmapDataView()进行10k个举行元素创建


测试结果:
1.1不使用BitmapData 内存占用 40M

2.1使用BitmapData 依旧内存占用 40M!
原因分析: 虽然_sqrList被设为null,但是原先被_sqrList所引用的1w个sprite数据依旧在内存中存在,虽然AMV2自带垃圾回收机,但是何时进行垃圾回收是不确定的。而要强制执行垃圾回收机,则要用上文提到的hack手段
2.2使用BitmapData + 垃圾回收hack 内存占用 12M


package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.net.LocalConnection;

public class MoonSpirit extends Sprite {
private const SQR_AMOUNT : int = 10000; //方块数量
private var _container_sp : Sprite; //容器sprite
private var _sqrList : Array; //所有方块的引用

public function MoonSpirit() {
init( );
}

private function init( ) : void{
_container_sp = new Sprite( );
addChild(_container_sp);
//initNoBitmapDataView( );
initBitmapDataView( );
}

//初始化 通过通常手段 显示
private function initNoBitmapDataView( ) : void {
layoutTenThousandSqr( );
}

//初始化 通过BitmapData快照 显示
private function initBitmapDataView( ) : void {
layoutTenThousandSqr( );
var myBitmapDataObject : BitmapData = new BitmapData(150, 150, false, 0xFF0000);
var myImage:Bitmap = new Bitmap(myBitmapDataObject);
addChild(myImage);
unLayoutTenThousandSqr( );
_sqrList = null;
doClearance( );
}

private function layoutTenThousandSqr( ) : void {
_sqrList = new Array( );
for(var i : int = 0; i < SQR_AMOUNT; i++){
_sqrList.push(new Sprite());
_sqrList[i].graphics.beginFill(0xff0000);
_sqrList[i].graphics.drawRect(0,0,100,100);
_sqrList[i].graphics.endFill();
_container_sp.addChild(_sqrList[i]);
}
}

//不显示
private function unLayoutTenThousandSqr( ) : void {
for(var i : int = 0; i < SQR_AMOUNT; i++){
_container_sp.removeChild(_sqrList[i]);
delete _sqrList[i];
}
}

//精髓,垃圾回收机强制调用
private function doClearance( ) : void {
trace("clear");
try{
new LocalConnection().connect("foo");
new LocalConnection().connect("foo");
}catch(error : Error){

}
}
}
}

广告:哈哈,现在刚好是阿里妈妈推广期哦,你是站长吗?推荐注册阿里妈妈赚广告费

TrackBack

TrackBack URL for this entry:
http://www.kingda.org/mt/mt-tb.cgi/215

Comments (9)

efish:

flashguru.co.uk很早就提到过这种方法,而且不建议使用。

dianlirui:

楼上这位大哥能解释为什么不建议使用吗?谢谢!

Jove:

Error handlering会消耗更多的性能,类似Java中的

efish:

sorry,昨天说错了,不是flashguru提出的,是gskinner。
文章找到了http://www.gskinner.com/blog/archives/2006/08/as3_resource_ma_2.html
他不建议使用的原话是“Again, this should only be used as a development aid. It should never be used in production code! There is an example of this in use in the demo FLAs for the WeakReference class, which you can download at the end of this article. ”。开发中小帮手,但是绝对不要在产品中使用。

to efish:
呵呵,谢谢认真的回复。
嗯,Grant的意见是对的。毕竟是unsupported way,不是长久之计。
不过目前倒是可以通过这个小技巧做一些小研究,哈哈。

ephay:

new LocalConnection().connect("foo");
为什么要调用2次?

aw:

回Jove:所谓的资源消耗,如果是与时间无关的(例如电路中的脉冲函数),我觉得倒也无妨。毕竟内存占用是“长久之害”。不知道我这样解释是否正确。

逸风:

黑羽老师,向你请教个问题.
主要想了解一下如何实时移动屏幕视窗(卷屏时移动屏幕视窗来变换显示区域,即地图不动而屏幕视窗动).
还有,Flash CS3中如何修改15 秒的默认超时设置

to ephay:
因为localconnection只可以有一个同名的连接,申明两个同名的连接就一定会产生异常,从而使得Flash Player执行回收。

留下高见,发表评论

个人信息不会外泄,请放心填写。

姓名和Email必填。

发表评论后,请耐心等待,不要频繁刷新。提交完成后,刷新一下本页即可看到您的评论。^_^

请输入验证字符"v" :
文字广告:你是站长吗?注册阿里妈妈赚广告费

最近发表

归档

全部
Creative Commons License
此 Blog 中的日记
遵循以下授权:
Creative Commons
(创作共用) 授权
.
Google PageRank
本站被Adobe官方MXNA新闻聚合器收录
本站被蓝色理想BXNA收录