Actionscript 3 AS3在BitmapData内存泄漏上绘制精灵

Actionscript 3 AS3在BitmapData内存泄漏上绘制精灵,actionscript-3,flash,memory-leaks,air,Actionscript 3,Flash,Memory Leaks,Air,我有一个AIR应用程序,可以从Flash编辑器渲染图像。您可以自定义多个曲面-它们都具有相同的宽度和高度。然后,每个曲面都由AIR应用程序渲染 我正在努力解决一个无法解决的内存泄漏问题 对于我需要渲染的每个曲面,我都有一个包含许多组件的精灵(其他精灵-一些具有事件侦听器、位图数据和其他子组件、精灵等) 我已经知道要进行垃圾收集的BitmapData问题,我测试了这两个问题: 为每个渲染创建一个新的位图数据,然后dispose()并指向null 为每次渲染重用单个位图数据 内存泄漏仍然以同样的

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

我正在努力解决一个无法解决的内存泄漏问题

对于我需要渲染的每个曲面,我都有一个包含许多组件的精灵(其他精灵-一些具有事件侦听器、位图数据和其他子组件、精灵等)

我已经知道要进行垃圾收集的BitmapData问题,我测试了这两个问题:

  • 为每个渲染创建一个新的位图数据,然后dispose()并指向null
  • 为每次渲染重用单个位图数据
内存泄漏仍然以同样的比例发生

这是我的循环:

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 
我觉得我在draw函数行为中遗漏了一些东西。看起来我已经创建了myBigSprite组件的新实例,这些实例在draw操作之后仍然存在

我试图在每个循环结束时完全销毁MyBigspite,它不会改变任何东西


任何暗示都将不胜感激

您应该在任何函数之外声明您的
Bitmap
BitmapData
,然后简单地在循环内部循环使用它们(而不是创建一个
新的
要添加到内存中的任何内容)

当您确定不再需要来自
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;
}

好了,伙计们,我终于明白并解决了这个问题

首先,我安装并运行了Adobe Scout。很好的工具

正如您可能看不到的(加上法语),我生成了3个与边对应的曲面。右侧的“大”绿色条消耗大量内存,表示“位图显示对象”。有趣!以前从没听说过

在谷歌搜索之后,我发现了这篇文章:

它解释了

例如,在前面显示的代码摘录中,加载 pict加载程序对象的操作完成后,pict对象将 加载一个子显示对象,即位图。访问 此位图显示对象,可以写入pict.getChildAt(0)

所以我开始不明白,不知何故,可能位图对象作为子对象附加在
myBigSprite
的某些对象上

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

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

private函数销毁显示对象(obj):无效{
if(obj中的“numChildren”){

对于(var i:int=0;i您如何知道垃圾收集进程运行了?您是否强制它?也正如旁注一样,通过调用System.gc()强制gc)据我所知,只在debug player中工作。正如您所见,绘图操作结束和下一个操作开始之间的内存几乎相等,但其间有许多内存消耗操作。特别是将位图编码为png。因此我假设GC进程正在完成其工作,因为我想要清理的所有资源都已被清除eaned除了draw函数外。我从未显式调用System.gc()。是否设置“结果”设置为null,因为它包含对bitmapdata的引用?是的,我编辑了我的代码段,因为它不清楚,对不起。@Bedu33通常情况下,垃圾收集器是惰性的,不会在任何未使用的内存未使用时立即处理。因此我建议您尝试调用System.gc()明确并查看内存测量值。如果这样做可以解决您的问题,那么这不是内存泄漏,而是GC懒惰。感谢您的回答。不幸的是,正如我在原始帖子中所说,我对重用的BitmapData得到了完全相同的结果。不过,我用您的解决方案再试了一次,并且我确认它具有相同的结果sult.Hmm,我不确定上次我是如何错过了“为每次渲染重复使用单个位图数据”的,但是,在循环中使用
new
是消耗内存的好方法。我的代码应该只是覆盖现有数据,所以无法理解如何以某种方式添加更多的新数据(增加内存使用量)。我将在可能的情况下研究如何使用闪存。“我的代码应该只是覆盖已经存在的数据,所以我无法理解如何以某种方式添加更多的新数据(增加内存使用量)”这也是我的问题:)
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;
    }
}