AS3 在 BitmapData 内存泄漏上绘制 Sprite

AS3 drawing Sprite on BitmapData memory leak

我有一个 AIR 应用程序可以从 Flash 编辑器渲染图像。您可以自定义多个表面 - 它们都具有相同的宽度和高度。然后每个表面都由 AIR 应用程序渲染。

我正在为无法解决的内存泄漏而苦苦挣扎。

对于我需要渲染的每个表面,我都有一个包含许多组件的 Sprite(其他 sprite - 一些具有事件侦听器、BitmapDatas 和其他子组件、sprite 等)。

我已经知道要进行垃圾回收的 BitmapData 问题,我都测试了:

内存泄漏仍然以相同的比例发生。

这是我的循环:

var bm:BitmapData = new BitmapData(destDim.x, destDim.y, true, bgColor);
var mtx:Matrix = new Matrix();
trace('before drawing :'+(System.privateMemory/1024));
bm.draw(myBigSprite, mtx, null, null, null, true);
trace('after drawing :'+(System.privateMemory/1024));
var result:Bitmap = new Bitmap(bm, PixelSnapping.NEVER, true);

//return result and encode Bitmap to png

result.bitmapData.dispose();
result.bitmapData = null;
result = null;

结果:

before drawing :208364
after drawing :302816
Wrote bitmap to file: surface0.png
before drawing :303296 
after drawing :446160 
Wrote bitmap to file: surface1.png 
before drawing :446160
after drawing :565212
Wrote bitmap to file: surface2.png 
before drawing :565924
after drawing :703100 
Wrote bitmap to file: surface3.png 
before drawing :703572
after drawing :834420 
Wrote bitmap to file: surface4.png 

我觉得我在绘图函数行为中遗漏了一些东西。似乎我新创建了 myBigSprite 组件的实例,这些实例在绘制操作后仍然存在。

我试图在每个循环结束时完全销毁 myBigSprite,它没有改变任何东西....

如有任何提示,我们将不胜感激!

你应该在任何函数之外声明你 BitmapBitmapData 然后简单地回收它们以在你的循环内使用(而不是创建一个 new 任何要添加的东西内存)。

当您确定不再需要来自 bm 变量的位图数据时,仅在最后一张图像上使用 .dispose()。否则,如果处置,您将必须再次创建一个新的替代方案 var someThing :BitmapData = new BitmapData 以供进一步使用。

////# declare globally (not inside some specific function..)

//var destDim :Point = new Point(your_X_num , your_Y_num);
//var bgColor :uint = 0x505050;

var bm:BitmapData = new BitmapData(destDim.x, destDim.y, true, bgColor);
var result:Bitmap = new Bitmap(bm, PixelSnapping.NEVER, true);
//result.bitmapData = bm; //can be set here but done within function for clarity...

var mtx:Matrix = new Matrix();


////# update bitmap by replacing its bitmapdata with new colour values of existing pixels

function Here_is_my_loop (): void 
{
    trace('before drawing :'+(System.privateMemory/1024));

    //overwrite pixel colours in bitmap (result)
    bm.draw(myBigSprite, mtx, null, null, null, true);
    result.bitmapData = bm; //update bitmap

    trace('after drawing :'+(System.privateMemory/1024));


    //return result and encode Bitmap to png

    //result.bitmapData.dispose();
    //result.bitmapData = null;
    //result = null;
}

好的,我终于理解并解决了这个问题。

首先,我安装了 运行 Adob​​e Scout。优秀的工具。

您可能看不到(加上它是法语),我生成了 3 个与边相对应的表面。右侧的 "big" 绿色条表示 "Bitmap display objects",这是大量内存消耗。有趣的 !以前从未听说过这些。

一Google搜索了一下,找到了这篇文章:https://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e26.html

它解释了

For example, in the code excerpt shown earlier, once the load operation for the pict Loader object is complete, the pict object will have one child display object, which is the bitmap, loaded. To access this bitmap display object, you can write pict.getChildAt(0).

所以我开始理解,也许 Bitmap 对象作为子对象附加在 myBigSprite 的某些对象上。

最后,我创建了一个递归函数来在 draw 操作之后搜索并销毁 myBigSprite 中包含的所有 BitmapBitmapDataByteArray 对象

//inside render function
bm.draw(myBigSprite, mtx, null, null, null, true);
destroyDisplayObjects(myBigSprite);

...

private function destroyDisplayObjects(obj):void{
    if ("numChildren" in obj){
        for (var i:int = 0; i<obj.numChildren; i++)
        {
            destroyDisplayObjects(obj.getChildAt(i));
        }
    }
    else {
        if (flash.utils.getQualifiedClassName(obj) == "flash.display::Bitmap"){
            //trace ('FREE BITMAP');
            obj.bitmapData.dispose();
            obj.bitmapData = null;
            obj = null;
            return;
        }
        else if (flash.utils.getQualifiedClassName(obj) == "flash.display::BitmapData"){
            //trace ('FREE BITMAPDATA');
            obj.dispose();
            obj = null;
            return;
        }
        else if (flash.utils.getQualifiedClassName(obj) == "flash.display::ByteArray"){
            //trace ('FREE BYTEARRAY');
            obj.clear();
            obj = null;
            return;
        }

        return;
    }
}

Et voilà,绘制操作后内存已 100% 清理,不再泄漏 :)