AS3 - 可用内存(加载程序、位图数据)?

发布于 2024-12-25 07:37:23 字数 2717 浏览 3 评论 0原文

由于某种原因,我的应用程序在运行时使用越来越多的内存,并且我不知道如何转储我不再需要的旧数据。

我使用 Loader 加载 .png 然后,我使用 BitmapData 来存储图像,以便我可以检查每个像素并存储结果。

然后我循环这个x次。

当我开始第二次运行时,我不再需要旧信息,但看起来我的应用程序仍在存储数据(加载的图像)。

这是我的一些代码:

        public function loadImage():void{
            myLoader = new Loader();
            myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);

            if (currentFrame.toString(10).length == 1){
                currentFrameURL = txtFolder.text + "\\" + txtImageName.text + txtImageNum.text.substr(0, txtImageNum.text.length - 1) + currentFrame + txtImageType.text;
            }
            if (currentFrame.toString(10).length == 2){
                currentFrameURL = txtFolder.text + "\\" + txtImageName.text + txtImageNum.text.substr(0, txtImageNum.text.length - 2) + currentFrame + txtImageType.text;
            }
            if (currentFrame.toString(10).length == 3){
                currentFrameURL = txtFolder.text + "\\" + txtImageName.text + txtImageNum.text.substr(0, txtImageNum.text.length - 3) + currentFrame + txtImageType.text;
            }
            trace(currentFrameURL + " sent to loader...");

            myLoader.load(new URLRequest(currentFrameURL));
        }

        public function imageLoaded(event:Event):void{
            myLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, imageLoaded);

            myBitmapData = new BitmapData(parseInt(txtWidth.text),parseInt(txtHeight.text),false);
            myBitmapData.draw(event.currentTarget.content);


            //Generate preview of current image being processed..
            //myPreviewImage.source = myBitmapData;
            labelProgress.text = "Current process: " + (currentFrame + 1) + "/" + (parseInt(txtFrames.text));


            for(var y:int=0; y < parseInt(txtHeight.text) ; y++){
                for(var x:int=0; x < parseInt(txtWidth.text) ; x++){
                    currentPixelColor = myBitmapData.getPixel(x,y);
                    myTabelClass.recordPixel(currentPixelColor);
                }
            }//ett bilde ferdig scannet og lagret

            currentFrame++;

            if(currentFrame < parseInt(txtFrames.text)){
                myTabelClass.newImg(currentFrame);
                trace("sending newImg command: " + currentFrame);
                loadImage();
            }else{
                //All frames done..
                //myTabelClass.traceResult();
                Alert.show("All images scanned!\n\nClick 'OK' to add new data to XML.", "Images scanned", Alert.OK, this, insertDataToXML);
                btnSave.enabled = true;
                btnTest1.enabled = true;
            }

        }

For some reason my app is using more and more memory as it runs, and I can't figure out how to dump old data I dont need anymore.

I use a Loader to load a .png
I then use a BitmapData to store the image, so that I can go over and check each pixel and store the result.

Then I loop this x times.

When I start on the second run I don't need the old information anymore, but it looks like my app is still storing the data (the images loaded)..

Here's some of my code:

        public function loadImage():void{
            myLoader = new Loader();
            myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);

            if (currentFrame.toString(10).length == 1){
                currentFrameURL = txtFolder.text + "\\" + txtImageName.text + txtImageNum.text.substr(0, txtImageNum.text.length - 1) + currentFrame + txtImageType.text;
            }
            if (currentFrame.toString(10).length == 2){
                currentFrameURL = txtFolder.text + "\\" + txtImageName.text + txtImageNum.text.substr(0, txtImageNum.text.length - 2) + currentFrame + txtImageType.text;
            }
            if (currentFrame.toString(10).length == 3){
                currentFrameURL = txtFolder.text + "\\" + txtImageName.text + txtImageNum.text.substr(0, txtImageNum.text.length - 3) + currentFrame + txtImageType.text;
            }
            trace(currentFrameURL + " sent to loader...");

            myLoader.load(new URLRequest(currentFrameURL));
        }

        public function imageLoaded(event:Event):void{
            myLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, imageLoaded);

            myBitmapData = new BitmapData(parseInt(txtWidth.text),parseInt(txtHeight.text),false);
            myBitmapData.draw(event.currentTarget.content);


            //Generate preview of current image being processed..
            //myPreviewImage.source = myBitmapData;
            labelProgress.text = "Current process: " + (currentFrame + 1) + "/" + (parseInt(txtFrames.text));


            for(var y:int=0; y < parseInt(txtHeight.text) ; y++){
                for(var x:int=0; x < parseInt(txtWidth.text) ; x++){
                    currentPixelColor = myBitmapData.getPixel(x,y);
                    myTabelClass.recordPixel(currentPixelColor);
                }
            }//ett bilde ferdig scannet og lagret

            currentFrame++;

            if(currentFrame < parseInt(txtFrames.text)){
                myTabelClass.newImg(currentFrame);
                trace("sending newImg command: " + currentFrame);
                loadImage();
            }else{
                //All frames done..
                //myTabelClass.traceResult();
                Alert.show("All images scanned!\n\nClick 'OK' to add new data to XML.", "Images scanned", Alert.OK, this, insertDataToXML);
                btnSave.enabled = true;
                btnTest1.enabled = true;
            }

        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

春花秋月 2025-01-01 07:37:23

完成 myBitmapData 后,调用 myBitmapData.dispose()myBitmapData = null。请记住,调用 dispose() 后,您的 BitmapData 对象将不再可用,因此您必须创建一个新实例 (myBitmapData = new BitmapData( ))。

顺便说一句,我没有对您的代码进行太多分析,但我注意到您使用 draw() 复制了每个图像的位图数据,然后对其进行处理。您可以直接使用加载的图像内容,这也可以节省内存:

myBitmapData = Bitmap(event.target.content).bitmapData;

并且不要忘记null如果您以后不打算使用它们,请先查看每个图像,然后再继续下一帧。

Once you're done with myBitmapData, call myBitmapData.dispose() and myBitmapData = null. Keep in mind that after you call dispose(), your BitmapData object is not usable anymore, so you have to create a new instance (myBitmapData = new BitmapData()).

By the way, I did not analyze you code much, but I've noticed that you copied each image's bitmapData with draw() and then worked on it. You could work directly with loaded images content, that would save memory as well:

myBitmapData = Bitmap(event.target.content).bitmapData;

and don't forget to null each image before proceeding to the next frame if you do not intend to use them later.

抹茶夏天i‖ 2025-01-01 07:37:23

不幸的是,有一个错误阻止加载程序释放内存,请参阅此处:https ://bugbase.adobe.com/index.cfm?event=bug&id=3071138。根据我的测试,这可能与您希望以多快的速度处理先前加载的内容有关,但这只是一个猜测,不要认为这是理所当然的。

其他事项:调用 BitmapData.dispose() 会“立即”释放内存,但如果不这样做,则 BitmapData 实例仍会被 GC,但是,这可能需要更长的时间,并且徘徊的位图可能会被回收。造成内存泄漏的印象。

System.gc() 仅在调试器中可用,这意味着您的最终用户将无法使用它。

在对象不再使用后,将变量(尤其是局部变量)设置为 null 是没有意义的,如果编译器稍微聪明一点,它可能会将其识别为死代码并完全删除。将数据成员设置为 null 仅当您实际上希望它们出于某种原因为 null 时才有用,这就是他们所说的“业务逻辑原因”,不要尝试“帮助”GC,您很可能会这样做弊大于利。当我遇到分配null的代码时,这通常会点亮一个红色灯泡,这是一个相当糟糕的设计或冗余。如果您的代码很好,则不需要这样做。

Unfortunately, there is a bug preventing Loader from ever freeing memory, see here: https://bugbase.adobe.com/index.cfm?event=bug&id=3071138 . As per my tests, it may be related to how fast do you want to dispose the previously loaded content, but this is a guess, don't take it for granted.

Other things: calling BitmapData.dispose() frees memory "immediately", but if you don't, then BitmapData instances are still GC'ed, however, that may take longer, and the loitering bitmaps may create an impression of a memory leak.

System.gc() is only available in debugger, which means that your end users will not be able to use it.

Setting variables, especially local variables to null, after the object is no longer used makes no sense, if the compiler was only a little smarter, it would probably identify it as a dead code and remove altogether. Setting data members to null is only useful if you actually want them to be null for whatever reason, which is as they call it, "a business logic reason", don't try to "help" the GC, all chances are you will do more harm then good. When I come across a code that assigns null, this usually lights a red bulb, it is rather a bad design, or redundancy. If your code is good, you shouldn't need to do it.

春花秋月 2025-01-01 07:37:23

您处于递归状态,所以是的,您不会释放加载的预览图像。

尝试在再次调用 loadImage() 之前设置 myBitmapData = null

如果没有发生任何事情,您可以尝试通过在 loadImage 之前调用 System.gc() 来强制垃圾收集器:

myBitmapData = null;
System.gc();
loadImage();

但这不是一个好的做法。 :P

如果没有任何效果,只需删除可能有帮助的递归内容即可。

You're in recursion, so yes, you don't release the preview image loaded.

Try to set myBitmapData = null before call loadImage() again.

If nothing happen you can try force a garbage collector by calling System.gc() before loadImage:

myBitmapData = null;
System.gc();
loadImage();

But thats not a good practice they say. :P

If nothing works just remove the recursion thing that may help.

奶气 2025-01-01 07:37:23

其他答案已经介绍了如何处理 BitmapData,但我注意到 Loader 似乎也保留了内存。不幸的是,除了我的经验之外,我无法指出任何具体来源。您可以尝试一下,看看效果如何:

将该行

myLoader = new Loader();

移出 loadImage() 函数,并在类构造函数中实例化该变量。这将允许您一遍又一遍地重复使用相同的 Loader 实例。

Other answers have covered how to deal with BitmapData but I've noticed that Loaders seem to hold on to memory as well. Unfortunately I cannot point to any specific sources other than my experience. You can give this a try to see what shakes out:

Move the line

myLoader = new Loader();

out of the loadImage() function and instantiate that variable in the class constructor. This will allow you to reuse the same Loader instance over and over again.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文