9RIA.com天地会 - Flash论坛

返回列表 发帖
天地人才库

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

-----------------------------------------------------------------------------------------
首先,要感谢校友学长“费gg”的帮助,提供了核心的hack技术的方法。

然后鉴于几天前一网友关于画上万个sprite之后内存增大问题,在此一并作一下讨论和解决。
-----------------------------------------------------------------------------------------

概述:AVM2理论上是自带垃圾回收机的,但是具体何时进行垃圾回收,理论上非人为所能控制,而我们若要强制启用垃圾回收机,则需要用一些非正规手段,比如如下会提到的手段。

关键字:垃圾回收

核心hack技术
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
  1. package {
  2.         import flash.display.Bitmap;
  3.         import flash.display.BitmapData;
  4.         import flash.display.Sprite;
  5.         import flash.net.LocalConnection;

  6.         public class MoonSpirit extends Sprite {
  7.                 private const SQR_AMOUNT                        : int = 10000;    //方块数量       
  8.                 private var _container_sp                : Sprite;          //容器sprite
  9.                 private var _sqrList                                : Array;           //所有方块的引用
  10.                
  11.                 public function MoonSpirit() {
  12.                         init( );                       
  13.                 }
  14.                
  15.                 private function init( ) : void{
  16.                         _container_sp = new Sprite( );
  17.                         addChild(_container_sp);
  18.                         //initNoBitmapDataView( );
  19.                         initBitmapDataView( );
  20.                 }
  21.                
  22.                 //初始化 通过通常手段 显示
  23.                 private function initNoBitmapDataView( ) : void {
  24.                         layoutTenThousandSqr( );
  25.                 }
  26.                
  27.                 //初始化 通过BitmapData快照 显示
  28.                 private function initBitmapDataView( ) : void {
  29.                         layoutTenThousandSqr( );
  30.                         var myBitmapDataObject : BitmapData = new BitmapData(150, 150, false, 0xFF0000);
  31.                         var myImage:Bitmap = new Bitmap(myBitmapDataObject);
  32.                         addChild(myImage);
  33.                         unLayoutTenThousandSqr( );
  34.                         _sqrList = null;
  35.                         doClearance( );
  36.                 }
  37.                
  38.                 private function layoutTenThousandSqr( ) : void {
  39.                         _sqrList = new Array( );
  40.                         for(var i : int = 0; i < SQR_AMOUNT; i++){
  41.                                 _sqrList.push(new Sprite());
  42.                                 _sqrList[i].graphics.beginFill(0xff0000);
  43.                                 _sqrList[i].graphics.drawRect(0,0,100,100);
  44.                                 _sqrList[i].graphics.endFill();
  45.                                 _container_sp.addChild(_sqrList[i]);
  46.                         }
  47.                 }
  48.                
  49.                 //不显示
  50.                 private function unLayoutTenThousandSqr( ) : void {
  51.                         for(var i : int = 0; i < SQR_AMOUNT; i++){
  52.                                 _container_sp.removeChild(_sqrList[i]);
  53.                                 delete _sqrList[i];
  54.                         }
  55.                 }
  56.                
  57.                 //精髓,垃圾回收机强制调用
  58.                 private function doClearance( ) : void {
  59.                         trace("clear");
  60.                         try{
  61.                                 new LocalConnection().connect("foo");
  62.                                 new LocalConnection().connect("foo");
  63.                         }catch(error : Error){
  64.                                
  65.                         }                       
  66.                 }
  67.         }
  68. }
复制代码

TOP

很好
很强大哇
http://www.actionscript3.cn/magicianzrh

TOP

好文!加精!
黑羽翔天◎足下八邦
欢迎来我的博客 :)
www.kingda.org  (AS3教程)

TOP

强制回收,我喜欢!!!
宫心计!富贵门!

TOP

NB哦,好文要顶!!!!!!!

TOP

今天刚买了书  还没收到 呵呵! 所以搞不清楚这个是什么!

那位 告诉我下 这个是什么代码有什么作用呀? 呵呵

TOP

发现正文漏加了一个批注

所谓强制执行垃圾回收机,是指通过故意使swf在运行时出错,然后throw出错误,而同时通过catch error来继续运行swf文件。而垃圾回收机则会在swf抛出错误的时候,被强制执行一次,以清除内存中无效的数据占用,减少资源的消耗。

TOP

原帖由 MoonSpirit 于 2007-10-14 14:09 发表
发现正文漏加了一个批注

所谓强制执行垃圾回收机,是指通过故意使swf在运行时出错,然后throw出错误,而同时通过catch error来继续运行swf文件。而垃圾回收机则会在swf抛出错误的时候,被强制执行一次,以清除内存中无效的数 ...


那只要产生个错误,用

try{
        a
}catch(error : Error){
}

不就行了

TOP

原帖由 gene 于 2007-10-14 14:24 发表


那只要产生个错误,用

try{
        a
}catch(error : Error){
}

不就行了



我当初也是这么理解的,不过从“费gg”处所学到的,包括自己所测试的,并不是所有的error throw都能触发垃圾回收机,而也只局限于某些特定的error,而上文的例子中的这一error恰为其中的一种error类型。

当然,再说得“虚幻”一些,听说!!改种hack办法,也是一位资深的adobe as3内部开发人员所提供的一种对于现有的AVM2的垃圾回收机制的人为触发的不得已的一种办法,当然,是真是假呢?~呵呵,本人也是能力和眼界有限咯。呵呵

TOP

首先谢谢MoonSpirit对我所提问题的回答。

关于AMV2的垃圾回收机制,我看了你的说明。理解如下:
使用as hack技术实际上是在运行时进行的强制垃圾回收,因为不确定AMV2何时会进行垃圾回收,所以在运行时,即使删除了spirit,但是内存也不一定会释放,所以通过抛出错误,强制调用其垃圾回收机制以获得内存释放。

但是对于你说的在这里使用BitmapData快照技术,我还是不太明白,用在这里是何用意。
本来我以为你是对每个spirit进行快照处理,以提高cache的速度,可是我看了下你的测试代码,似乎只是对一个150*150大小的方格执行快照处理,而那10000个小方块,只是在渲染后,删除,并未进行快照处理。


其实更详细的说下我上次那个问题的想法:
    可能我会拥有一个spirit(可能是个movieclip),需要在flash文件中重复利用,比如同时显示出来,但是以目前可行的办法,只能,new 10000个这样的spirit出来,但是会造成运算超时,因为有可能我每帧都在进行运算处理,这样效率很低。
    我当初的想法是能否类似dx的方法,只在内存中保存一份资源,但是提交到显存中的时候,可以实现多份拷贝,将目标渲染在不同的位置上。因为我对AMV2的模拟机制还不是太熟悉,所以想请教下在flash中能否实现这样的想法。
请先忘记一切的生存压力,想想这辈子你最想要的是什么?
所以,最要紧的事情,先想好自己想要什么

TOP

  1. //不显示
  2.                 private function unLayoutTenThousandSqr( ) : void {
  3.                         for(var i : int = 0; i < SQR_AMOUNT; i++){
  4.                                 _container_sp.removeChild(_sqrList[i]);
  5.                                 delete _sqrList[i];
  6.                         }
  7.                 }
复制代码


这里 delete _sqrList[ i ]; 改成 _sqrList[ i ] = null;  可以吗?我比较习惯 =null,很少用delete.  不知道功能是否一样?

TOP

我的经验:
   将引用置为null只是使它所指向的对象为空,但是并不删除所指向的对象。只有用delete才能删除资源,释放内存。

不知道用在这里是不是一样的道理
请先忘记一切的生存压力,想想这辈子你最想要的是什么?
所以,最要紧的事情,先想好自己想要什么

TOP

原帖由 Lyang 于 2007-10-16 16:04 发表
我的经验:
   将引用置为null只是使它所指向的对象为空,但是并不删除所指向的对象。只有用delete才能删除资源,释放内存。

不知道用在这里是不是一样的道理 ...


这是一个有关as3数据变量类型的问题。首先,鉴于时间有限,自己也没有详细地去查相关的资料来给与完整的参考,但是自己曾经在一片文字中看到过关于变量的实质特点。
比如Array和Object类的数据类型都是属于指向性的,粗俗地说,可以把它们理解为一种指针变量,他们指向物理地址。而又如int,Number等属于实指类型,即他们的数据读写本身就在物理地址上。

所以,对于指向性的数据类型,比如Array格式,引用设置为null,只是将Array数据的指针指向了null。而原先所指向的物理地址的数据没有改变。再则,用delete的话,也只是将指针删除而已,而非将物理内存中数据清除。

不知道是否自己认识肤浅,要将指向型数据的数据清空,或许只有依靠垃圾回收机了哟~

TOP

原帖由 Lyang 于 2007-10-15 11:34 发表
首先谢谢MoonSpirit对我所提问题的回答。

关于AMV2的垃圾回收机制,我看了你的说明。理解如下:
使用as hack技术实际上是在运行时进行的强制垃圾回收,因为不确定AMV2何时会进行垃圾回收,所以在运行时,即使删 ...


我当初想给你提供的一种优化想法有点类似于ps中的合并图层的概念。

比如有1w各sprite在stage下同时存在,那么,或许就会有1w个sprite的数据元记录相关信息。

而用BitmapData的作用则是将那1w个sprite数据类型整个到一个BitmapData数据类型中,从而1w各数据元相对于1个数据元,是否实现了一种精简呢?

而BitmapData应该是将某一个瞬间,舞台上所见的像素信息进行截图,并保存。这样,既然有了那个瞬间所需可视像素信息,那么,那些多余的1w各sprite就不再需要,删除了,以释放出内存来。

至于执行效率么,毕竟有1w各数据类型放在那边,效率肯定会有所折扣。而我的能力,所能想到的方案,或许也就是用快照来“合并数据”,从而优化。但愿能有更好的办法咯~

TOP

返回列表