0

我有2节课。模拟流体。这两个类都非常简单和简短,但是在运行 2 秒后,模拟变得非常慢,看起来像是内存泄漏。但我在这段代码中看不到任何泄漏。

如果您能弄清楚,请告诉我,为什么会这样?

FluidLayer.as

package  {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;


public class FluidLayer extends MovieClip {

    private var canvas:Sprite;
    private var b:Bitmap;
    private var blur:BlurFilter = new BlurFilter(20,20,3);  
    private var bmd1:BitmapData;

    public function FluidLayer() {
        canvas = new Sprite();

        for(var i:int = 0;i < 600;i++){

            var p:Particle = new Particle();
            canvas.addChild(p);
            p.x = stage.stageWidth * Math.random();
            p.y = stage.stageHeight* Math.random();
            p.initi(stage);
        }

        canvas.filters = new Array(blur);
        addEventListener(Event.ENTER_FRAME, render);


    }


    private function render(e:Event):void{

        remove();

        b = new Bitmap(makeFluid(canvas),"auto", true);
        b.alpha = 0.7;
        addChild(b);

    }

    private function makeFluid(o:Sprite):BitmapData{

        bmd1 = new BitmapData(stage.stageWidth, stage.stageHeight, true);
        bmd1.draw(o,null,null,null,null,true);
        bmd1.threshold(bmd1, bmd1.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);

        return bmd1;
    }


    private function remove():void{
            if(numChildren > 1)
            removeChildAt(1);

            if(bmd1){ 
                bmd1.dispose();
                bmd1 = null;
            }
    }

}}

粒子.as

package  {

import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;


public class Particle extends MovieClip {

    private var speedX:int;
    private var speedY:int;
    private var _s:Stage;       

    public function Particle() {
        this.graphics.beginFill(0x00CCFF);
        this.graphics.drawCircle(0,0,Math.random() * 30);

        speedX = Math.random() * 10 - 5;
        speedY = Math.random() * 10 - 5;

        this.addEventListener(Event.ADDED_TO_STAGE, initi);

    }

    public function initi(s:Stage):void{
        this._s = s;
        addEventListener(Event.ENTER_FRAME, render);
    }       

    private function render(e:Event):void{

        this.x += Math.random()*speedX;
        this.y += Math.random()*speedY;


        if(this.x > _s.stageWidth || this.y > _s.stageHeight){

            //this.x =  Math.random()*_s.stageWidth;
            //this.y =  Math.random()*_s.stageHeight;

            removeEventListener(Event.ENTER_FRAME, render);
            this.parent.removeChild(this);
        }
    }
}}
4

3 回答 3

0

最初的减速似乎是画布上的模糊滤镜。(将过滤器注释掉以查看证明)

由闪存(CacheAsBitmap 和位图过滤器缓冲区)自动创建位图以渲染过滤器可能会导致内存泄漏,这可能是由于粒子运动导致画布尺寸不断变化。

在创建画布后尝试添加此行以进行快速修复:

canvas.scrollRect = new Rectangle(0,0,stage.stageWidth,stage.stageHeight);

通过使用 scrollRect 限制画布的大小,我们停止了这种重新分配。

然而,流体不再流向舞台的边缘。这可以在绘图和位图分配例程中解决,增加尺寸和偏移,我会让你试一试,但它部分与模糊滤镜量有关。

我建议将这些想法与 Andreas 代码中的非常好的想法相结合。

于 2013-08-15T00:12:09.213 回答
0

因此,我在 Andreas 和 adamh 的帮助下为我的问题制定了一个解决方案。

安德烈亚斯 - 告诉我我忘了处理位图数据(真的很好!)

Adamh - 告诉我在画布上定义 scrollrect(提高了很多性能!)

但最终是什么让性能变得流畅,这对我来说是一个简单的错误。我在particle.as > render() 中注意到,我只检查粒子是否在两侧(facepalm)超出范围,这是愚蠢的错误。当我更改渲染功能以检查剩余的 2 面时,它解决了性能问题。

抱歉这个愚蠢的问题:) 再次感谢 Andreas 和 adamh

最后的课程:

FluidLayer.as

package  {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;
import flash.geom.Rectangle;


public class FluidLayer extends MovieClip {

    private var canvas:Sprite;
    private var b:Bitmap;
    private var blur:BlurFilter = new BlurFilter(20,20,3);  
    private var bmd1:BitmapData;

    public function FluidLayer() {
        canvas = new Sprite();
        canvas.scrollRect = new Rectangle(0,0,1010,550);
        for(var i:int = 0;i < 600;i++){

            var p:Particle = new Particle();
            canvas.addChild(p);
            p.x = stage.stageWidth * Math.random();
            p.y = stage.stageHeight* Math.random();
            p.initi(stage);
        }

        canvas.filters = new Array(blur);
        addEventListener(Event.ENTER_FRAME, render);


    }


    private function render(e:Event):void{

        remove();

        b = new Bitmap(makeFluid(canvas),"auto", true);
        b.alpha = 0.7;
        addChild(b);

    }

    private function makeFluid(o:Sprite):BitmapData{

        bmd1 = new BitmapData(stage.stageWidth, stage.stageHeight, true);
        bmd1.draw(o,null,null,null,null,true);
        bmd1.threshold(bmd1, bmd1.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);

        return bmd1;
    }


    private function remove():void{
            if(numChildren > 1)
            removeChildAt(1);

            if(bmd1){ 

                bmd1.dispose();
                bmd1 = null;
            }
    }}}

粒子.as

package  {

import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;


public class Particle extends MovieClip {

    private var speedX:int;
    private var speedY:int;
    private var _s:Stage;       

    public function Particle() {
        this.graphics.beginFill(0x00CCFF);
        this.graphics.drawCircle(0,0,Math.random() * 30);

        speedX = Math.random() * 10 - 5;
        speedY = Math.random() * 10 - 5;

        this.addEventListener(Event.ADDED_TO_STAGE, initi);

    }

    public function initi(s:Stage):void{
        this._s = s;
        addEventListener(Event.ENTER_FRAME, render);
    }       

    private function render(e:Event):void{

        this.x += Math.random()*speedX;
        this.y += Math.random()*speedY;


        if(this.x > _s.stageWidth || this.y > _s.stageHeight || this.x < 0 && this.y < 0){

            this.x =  Math.random()*_s.stageWidth;
            this.y =  Math.random()*_s.stageHeight;

            //removeEventListener(Event.ENTER_FRAME, render);
            //this.parent.removeChild(this);
        }
    }
}}
于 2013-08-15T16:00:56.740 回答
0

您必须调用 bmd1.dispose(); 在重新实例化它之前,否则它不会从内存中释放位图。

编辑:

在非常仔细地查看了您的代码、优化它并清理了一些东西之后,我得出的结论是,您的模拟不再运行越来越慢。

问题在于您计算粒子 x 和 y 速度的方式。从本质上讲,它会降低速度,直到一起停止。除了您放置的大量高质量模糊和缺少释放位图之外,您的电影会出现并且实际上会缓慢爬行。

这是我修改过的代码。我对它进行了基准测试,15 分钟后它的峰值没有超过 10% cpu 或 40k 内存。

粒子.as

package  {

import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;


public class Particle extends MovieClip {

    private var speedX:int;
    private var speedY:int;  
    private var deleted:Boolean = false;

    public function Particle() {
        this.graphics.beginFill(0x00CCFF);
        this.graphics.drawCircle(0,0,Math.random() * 30);

        //The max prevents particle speed from rounding to zero.
        speedX = Math.ceil(Math.random() * 10 - 5);
        speedY = Math.ceil(Math.random() * 10 - 5);
    }     

    public function render():void{
        //It originally appeared to be slowing down. In-fact, it was.
        x += Math.random() * speedX;
        y += Math.random() * speedY;

        deleted = (x > FluidLayer.w || y > FluidLayer.h);
        //Comment this below if you want particles to be removed once they go out of bounds.
        if(deleted) {
            x = Math.random() * FluidLayer.w;
            y = Math.random() * FluidLayer.h;
            deleted = false;
        }
    }

    public function isDeleted():Boolean {
        return deleted;
    }
}
}

FluidLayer.as

package  {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;


public class FluidLayer extends MovieClip {

    private var canvas:Sprite;

    private var bitmap:Bitmap;
    private var bitmapData:BitmapData;

    private var particleArray:Array = new Array();

    public static const w:uint = 550;
    public static const h:uint = 400;


    public function FluidLayer() {
        addEventListener(Event.ADDED_TO_STAGE, initialize);
    }

    //By only one event handler to render, we prevent the overhead of 599 bubbling events.
    private function render(e:Event):void {
        for each(var p:Particle in particleArray) {
            p.render();
            //uncomment below if you want particles to become removed when they navigate out of bounds.
            //if(p.isDeleted()) {
                //canvas.removeChild(p);
                //particleArray.splice(particleArray.indexOf(p),1); 
            //}
        }
        bitmapData.fillRect(bitmapData.rect, 0); //clear the bitmapdata
        bitmapData.draw(canvas,null,null,null,null,true);
        bitmapData.threshold(bitmapData, bitmapData.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);
    }


    //We call initialize once the fluid layer has been added to stage 
    //or else stage values will be null.
    private function initialize(e:Event):void {
        canvas = new Sprite();


        //You DEFINITELY want to lower the blur amount here.
        //This is what is ultimately slowing your SWF down to a crawl.
        //canvas.filters = new Array(new BlurFilter(20,20,1));

        for(var i:uint = 0; i < 600; i++) {
            var p:Particle = new Particle();
            p.x = Math.random() * w;
            p.y = Math.random() * h;
            canvas.addChild(p);
            particleArray.push(p);
        }

        //The bitmap and bitmapData only need to be initialized once
        bitmapData = new BitmapData(w, h, true);

        bitmap = new Bitmap(bitmapData, "auto", true);
        bitmap.alpha = 0.7;
        addChild(bitmap);

        addEventListener(Event.ENTER_FRAME, render);
    }


}
}
于 2013-08-14T17:52:37.117 回答