天天看點

AS3遊戲中可視對象上限及位圖相關的記憶體消耗實測

前些天連續做了一些測試,以加深對AS3的掌握和在項目中對 遊戲 性能、效率優化方面的一些處理,有很多測試實際意義不大,都不過是證明一些猜想是正确的,除此沒有什麼。

但前天進行的一系列測試中,有一些對遊戲開發中的記憶體占用,CPU占用方面有些意義,我打算逐漸寫幾篇讨論性的文章與大家共享。

由于最近在做的是2D的等距視角遊戲,全部采用的位圖處理,與3D無關,是以關注的也是這方面的問題,考慮問題的出發點也是這些方面,是以關注面還是比較狹窄的。

   一、先從這類2D遊戲中常用的對象類型的簡單測試來開始看AS3的底層是如何支援

這隻能是管窺一斑,我也隻能是據此做點猜測,至于AS3底層到底如何實作,大可不必去搞的很清楚,但測試的結果卻可以在我們寫代碼時,作到心中有數。

先來看測試函數代碼

private function compareDisplayObject():void  

{  

        len1 = System.totalMemory;  

        _txt.text = "測試前總記憶體大小為:" + len1.toString();  

        var sprite:Sprite = new Sprite();  

        len2 = System.totalMemory;  

        _txt.appendText("\nnew Sprite後總記憶體大小為:" + len2.toString());  

        _txt.appendText("\nnew Sprite後增加的記憶體為:" + (len2 - len1).toString());  

        var bmp:Bitmap = new Bitmap();  

        len1 = System.totalMemory;  

        _txt.appendText("\n\nnew Bitmap後總記憶體大小為:" + len1.toString());  

        _txt.appendText("\nnew Bitmap後增加的記憶體為:" + (len1 - len2).toString());  

        var shape:Shape = new Shape();  

        len2 = System.totalMemory;  

        _txt.appendText("\n\nnew Shape後總記憶體大小為:" + len2.toString());  

        _txt.appendText("\nnew Shape後增加的記憶體為:" + (len2 - len1).toString());  

        var rect:Rectangle = new Rectangle(0, 0, 200, 100);  

        len1 = System.totalMemory;  

        _txt.appendText("\n\nnew Rectangle,大小為200*100後總記憶體大小為:" + len1.toString());  

        _txt.appendText("\nnew Rectangle,大小為200*100後增加的記憶體為:" + (len1 - len2).toString());  

        //注釋掉下面一段,單獨測試将sprite、bmp、shape三個空對象添加到顯示清單。  

        sprite.graphics.drawRect(0, 0, 200,100);  

        len2 = System.totalMemory;  

        _txt.appendText("\n\nsprite繪制200*100的矩形後總記憶體大小為:" + len2.toString());  

        _txt.appendText("\nsprite繪制200*100的矩形後增加的記憶體為:" + (len2 - len1).toString());  

        shape.graphics.drawRect(0,0,200,100)  

        len1 = System.totalMemory;  

        _txt.appendText("\n\nshape繪制200*100的矩形後總記憶體大小為:" + len1.toString());  

        _txt.appendText("\nshape繪制200*100的矩形後增加的記憶體為:" + (len1 - len2).toString());  

        this.addChild(sprite);  

        len2 = System.totalMemory;  

        _txt.appendText("\n\n将sprite添加到舞台後總記憶體大小為:" + len2.toString());  

        _txt.appendText("\nsprite添加到舞台後增加的記憶體為:" + (len2 - len1).toString());  

        this.addChild(bmp);  

        len1 = System.totalMemory;  

        _txt.appendText("\n\n将bmp添加到舞台後總記憶體大小為:" + len1.toString());  

        _txt.appendText("\nbmp添加到舞台後增加的記憶體為:" + (len1 - len2).toString());  

        this.addChild(shape);  

        len2 = System.totalMemory;  

        _txt.appendText("\n\n将shape添加到舞台後總記憶體大小為:" + len2.toString());  

        _txt.appendText("\nshape添加到舞台後增加的記憶體為:" + (len2 - len1).toString());  

}  

再來看輸出結果:

//------------------------------------------------>

  測試前總記憶體大小為:3162112

new Sprite後總記憶體大小為:3162112

new Sprite後增加的記憶體為:0

new Bitmap後總記憶體大小為:3162112

new Bitmap後增加的記憶體為:0

new Shape後總記憶體大小為:3170304

new Shape後增加的記憶體為:8192

new Rectangle,大小為200*100後總記憶體大小為:3182592

new Rectangle,大小為200*100後增加的記憶體為:12288

sprite繪制200*100的矩形後總記憶體大小為:3190784

sprite繪制200*100的矩形後增加的記憶體為:8192

shape繪制200*100的矩形後總記憶體大小為:3198976

shape繪制200*100的矩形後增加的記憶體為:8192

将sprite添加到舞台後總記憶體大小為:3207168

sprite添加到舞台後增加的記憶體為:8192

将bmp添加到舞台後總記憶體大小為:3211264

bmp添加到舞台後增加的記憶體為:4096

将shape添加到舞台後總記憶體大小為:3215360

shape添加到舞台後增加的記憶體為:4096

   //------------------------------------------------>

  前天測試時,每次運作FP,第一次基本上new Sprite,Bitmap,Shape後增加的記憶體都不為0,前二者都是4096,Shape是8192,但今天每次重新運作前面兩個對象new 後記憶體增加都是0。

運作以後,多次調用這個函數,輸出的内容可以看到記憶體每次重複調用時都在之前基礎上增加,但這幾個new 操作之後,記憶體的增加經常0,而Shape為0的時候很少,多數是4096,偶爾是8192。

我猜測,這應該是運作時環境認為new 出來的執行個體,沒有使用,并且引用計數也是0,是以被回收了,這從輸出内容的後面一些部分(對象被添加到顯示清單中),所顯示的記憶體增加始終大于0可以看出來。

但是反複調用這個函數時,将sprite執行個體添加到顯示清單中,使得增加的記憶體數卻經常在4096和8192之間變動,這讓我感到很是疑惑,想不到合理的解釋。

   二、對sprite,bitmap,shape  new 一批空對象,及将一批空對象添加到顯示清單的記憶體占用測試

這裡說的空對象不是指null的無值情況,而是僅指new之後,不加任何處理或指派的情況。

先來看測試代碼:

[javascript]  view plaincopyprint?

private function compareMultiDisplayObject():void  

{  

        //每類對象new的個數   

        var num:uint = 1000;                          

        len1 = System.totalMemory;  

        _txt.text = "每次建立" + num.toString() + "個同類對象,測試前總記憶體大小為:" + len1.toString();  

        var i:uint;  

        var sprite:Sprite;  

        var bmp:Bitmap;  

        var shape:Shape;  

        for (i = 0; i < num; i++)   

        {  

                sprite = new Sprite();  

                //恢複以下注釋,讓new出來的對象有引用計數,避免對象被認為無使用而被回收  

                //arr.push(sprite);  

        }  

        len2 = System.totalMemory;  

        _txt.appendText("\nnew Sprite後總記憶體大小為:" + len2.toString());  

        _txt.appendText("\nnew Sprite後增加的記憶體為:" + (len2 - len1).toString() + " || 平均每個增加:" + ((len2 - len1)/num).toString());  

        for (i = 0; i < num; i++)   

        {  

                bmp = new Bitmap();  

                //arr.push(bmp);  

        }                          

        len1 = System.totalMemory;  

        _txt.appendText("\n\nnew Bitmap後總記憶體大小為:" + len1.toString());  

        _txt.appendText("\nnew Bitmap後增加的記憶體為:" + (len1 - len2).toString() + " || 平均每個增加:" + ((len1 - len2)/num).toString());  

        for (i = 0; i < num; i++)   

        {  

                shape = new Shape();  

                //arr.push(shape);   

        }                          

        len2 = System.totalMemory;  

        _txt.appendText("\n\nnew Shape後總記憶體大小為:" + len2.toString());  

        _txt.appendText("\nnew Shape後增加的記憶體為:" + (len2 - len1).toString() + " || 平均每個增加:" + ((len2 - len1)/num).toString());  

        _txt.appendText("\n\n================以下為建立并添加到顯示清單================");  

        for (i = 0; i < num; i++)   

        {  

                sprite = new Sprite();  

                this.addChild(sprite);  

        }  

        len1 = System.totalMemory;  

        _txt.appendText("\nnew Sprite後總記憶體大小為:" + len1.toString());  

        _txt.appendText("\nnew Sprite後增加的記憶體為:" + (len1 - len2).toString() + " || 平均每個增加:" + ((len1 - len2)/num).toString());  

        for (i = 0; i < num; i++)   

        {  

                bmp = new Bitmap();  

                this.addChild(bmp);  

        }                          

        len2 = System.totalMemory;  

        _txt.appendText("\n\nnew Bitmap後總記憶體大小為:" + len2.toString());  

        _txt.appendText("\nnew Bitmap後增加的記憶體為:" + (len2 - len1).toString() + " || 平均每個增加:" + ((len2 - len1)/num).toString());  

        for (i = 0; i < num; i++)   

        {  

                shape = new Shape();

this.addChild(shape);  

        }                          

        len1 = System.totalMemory;  

        _txt.appendText("\n\nnew Shape後總記憶體大小為:" + len1.toString());  

        _txt.appendText("\nnew Shape後增加的記憶體為:" + (len1 - len2).toString() + " || 平均每個增加:" + ((len1 - len2)/num).toString());  

}  

  前一部分測試是建立一批空對象,不作任何其他的操作,那麼這些對象的引用計數應該是0

後面一部分測試是建立一批空對象,并将建立的每個對象随後添加到了顯示清單,那麼這批對象就同時有了引用計數,也即不對這些對象進行其他處理情況下的記憶體占用。但對Bitmap對象還是略有不同,因為并有為其new 一個bitmapData對象執行個體,是以bitmap所占記憶體這裡輸出的要比實際的低

下面來看測試輸出:

  //------------------------------------------------------------------------------->

  每次建立1000個同類對象,測試前總記憶體大小為:3158016

new Sprite後總記憶體大小為:3665920

new Sprite後增加的記憶體為:507904 || 平均每個增加:507.904

new Bitmap後總記憶體大小為:3788800

new Bitmap後增加的記憶體為:122880 || 平均每個增加:122.88

new Shape後總記憶體大小為:4141056

new Shape後增加的記憶體為:352256 || 平均每個增加:352.256

================以下為建立并添加到顯示清單================

new Sprite後總記憶體大小為:3760128

new Sprite後增加的記憶體為:-380928 || 平均每個增加:-380.928

new Bitmap後總記憶體大小為:4505600

new Bitmap後增加的記憶體為:745472 || 平均每個增加:745.472

new Shape後總記憶體大小為:4886528

new Shape後增加的記憶體為:380928 || 平均每個增加:380.928

  //-------------------------------------------------------------------------------->

  可以看到輸出中的這段:

  //------------------------------------------------------------->

  new Sprite後總記憶體大小為:3760128

new Sprite後增加的記憶體為:-380928 

  //------------------------------------------------------------->

  記憶體增加是負值,如果看作是之前new 出的一批對象執行個體被回收了,重新建立一批Sprite執行個體,并添加到顯示清單中,比之前僅建立Sprite而不添加到顯示清單的記憶體“new Sprite後總記憶體大小為:3665920”相比來說,還算是比較合理的。

是以這個負值也就不意外了。

另外,從這個測試函數内的源碼注釋部分,可以看到“arr.push(sprite);”這樣幾行,是當時測試new 出來的這一批對象,不添加到顯示清單,僅僅增加引用計數而進行的測試,可以與添加到顯示清單的記憶體開銷進行一下對比。

  //-------------------------------------------------------------------------------->

  每次建立1000個同類對象,測試前總記憶體大小為:3158016

new Sprite後總記憶體大小為:3670016

new Sprite後增加的記憶體為:512000 || 平均每個增加:512

new Bitmap後總記憶體大小為:4444160

new Bitmap後增加的記憶體為:774144 || 平均每個增加:774.144

new Shape後總記憶體大小為:4796416

new Shape後增加的記憶體為:352256 || 平均每個增加:352.256

================以下為建立并添加到顯示清單================

new Sprite後總記憶體大小為:5373952

new Sprite後增加的記憶體為:577536 || 平均每個增加:577.536

new Bitmap後總記憶體大小為:6160384

new Bitmap後增加的記憶體為:786432 || 平均每個增加:786.432

new Shape後總記憶體大小為:6500352

new Shape後增加的記憶體為:339968 || 平均每個增加:339.968

  //---------------------------------------------------------------------------------->

  看兩段輸出,很清楚,可以對比着看,不解釋。

  三、對圖檔加載和位圖常用操作的對比測試

先看測試函數,這個函數寫的還早,測試的還早,是以對輸出文字的處理跟前面兩個有點不一樣。

private function compareBitmap():void  

{  

        var loader:Loader = new Loader();  

        var path:String = "1.png";  

        var url:URLRequest = new URLRequest(path);  

        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoader_Complete);  

        len2 = System.totalMemory;  

        _txt.text = "載入圖檔前總記憶體大小為:" + len2.toString();  

        loader.load(url);  

}  

private function imageLoader_Complete(e:Event):void  

{  

        var text:String;  

        len1 = System.totalMemory;  

        text = _txt.text + "\n載入圖檔後總記憶體大小為:" + len1.toString();  

        text += "\n載入後增加的記憶體大小為:" + (len1 - len2).toString();  

        var loader:Loader = e.target.loader as Loader;  

        var bmp:Bitmap = loader.content as Bitmap;  

        text += "\n\nloader的總位元組數為:" + loader.contentLoaderInfo.bytesTotal.toString();  

        text += "\nBitmap的總位元組數為:" + bmp.loaderInfo.bytesTotal.toString();  

        text += "\n目前總記憶體大小為:" + System.totalMemory.toString();  

        var bmpData:BitmapData = bmp.bitmapData;  

        len2 = System.totalMemory;  

        text += "\n\nBitmapData指派後的總記憶體大小為:" + len2.toString();  

        bmpData.copyPixels(bmp.bitmapData, new Rectangle(0,0,bmp.width,bmp.height), new Point(0, 0));  

        len1 = System.totalMemory;  

        text += "\ncopyPixels位圖對象的bitmapData後的總記憶體大小為:" + len1.toString();  

        bmpData.draw(bmp);  

        len2 = System.totalMemory;  

        text += "\nbitmapData.draw()位圖對象後的總記憶體大小為:" + len2.toString();  

        var bmp1:Bitmap = new Bitmap();  

        text += "\nnew一個Bitmap空對象bmp1後的總記憶體大小為:" + System.totalMemory.toString();  

        bmp1.bitmapData = bmpData;  

        text += "\n對bmp1.bitmapData指派後的總記憶體大小為:" + System.totalMemory.toString();  

        var bmp2:Bitmap = new Bitmap(bmpData);  

        text += "\n使用得到的bmpData對象生成bmp2後的總記憶體大小為:" + System.totalMemory.toString();  

        this.addChild(bmp1);  

        text += "\n将bmp1添加到顯示清單後的總記憶體大小為:" + System.totalMemory.toString();  

        this.addChild(bmp2);  

        text += "\n将bmp2添加到顯示清單後的總記憶體大小為:" + System.totalMemory.toString();  

        bmp1.x = 300;  

        bmp1.y = 0;  

        bmp2.x = 400;  

        bmp2.y = bmp2.height + 10;  

        text += "\n\n圖檔寬度=" + bmp.width.toString() + ",高度=" + bmp.height.toString();  

        text += "\n按PNG圖檔像素記憶體占用<ARGB*width*height>\n來計算,則純像素占記憶體= 4 * " + bmp.width.toString() + " * " + bmp.height.toString() + " =" + (4 * bmp.width * bmp.height).toString();;  

        len2 = System.totalMemory;  

        text += "\n\n目前總記憶體大小為:" + len2;  

        bmpData = bmp.bitmapData.clone();  

        len1 = System.totalMemory;  

        text += "\n克隆位圖對象的bitmapData後的總記憶體大小為:" + len1.toString();  

        text += "\n克隆後增加的記憶體大小為:" + (len1 - len2).toString();  

        var num:uint = 1000;  

        var j:uint;  

        var tempBMP:Bitmap;  

        var rect:Rectangle = new Rectangle(0, 0, bmp.width, bmp.height);  

        var vertex:Point = new Point(0, 0);  

        var dt:int = getTimer();  

        len2 = System.totalMemory;  

        text += "\n\nnum=" + num.toString() + " || 目前總記憶體大小為:" + len2;                          

        for (j = 0; j < num; j++)   

        {  

                tempBMP = new Bitmap();  

                //tempBMP.bitmapData = bmp.bitmapData;  

                tempBMP.bitmapData = new BitmapData(bmp.width, bmp.height);  

                tempBMP.bitmapData.copyPixels(bmp.bitmapData, rect, vertex);  

                this.addChild(tempBMP);  

                tempBMP.x = j + 300;  

                tempBMP.y = j;  

        }  

        len1 = System.totalMemory;  

        dt = getTimer() - dt;  

        text += "\n生成num個位圖并添加到顯示清單中後的總記憶體大小為:" + len1.toString();  

        text += "\n生成num個位圖并添加到顯示清單中後增加的記憶體大小為:" + (len1 - len2).toString();  

        text += "\n花費時間:" + dt.toString() + "毫秒 || 平均操作每個對象需時:" + (dt / num).toString();  

        _txt.text = text;  

}  

對上面這段代碼裡面的for循環裡面部分,以循環1000次為例,我進行三種測試。

for (j = 0; j < num; j++)   

{  

        tempBMP = new Bitmap(bmp.bitmapData);  

        this.addChild(tempBMP);  

        tempBMP.x = j + 300;  

        tempBMP.y = j;  

}

上面這種測試由載入的bitmapData直接生成要使用的位圖,以友善添加到顯示清單中使用。

上面這種測試輸出是:

  //------------------------------------------------------------------------->

  載入圖檔前總記憶體大小為:3174400

載入圖檔後總記憶體大小為:3526656

載入後增加的記憶體大小為:352256

loader的總位元組數為:61831

Bitmap的總位元組數為:61831

目前總記憶體大小為:3526656

BitmapData指派後的總記憶體大小為:3526656

copyPixels位圖對象的bitmapData後的總記憶體大小為:3526656

bitmapData.draw()位圖對象後的總記憶體大小為:3526656

new一個Bitmap空對象bmp1後的總記憶體大小為:3526656

對bmp1.bitmapData指派後的總記憶體大小為:3526656

使用得到的bmpData對象生成bmp2後的總記憶體大小為:3526656

将bmp1添加到顯示清單後的總記憶體大小為:3526656

将bmp2添加到顯示清單後的總記憶體大小為:3526656

圖檔寬度=256,高度=255

按PNG圖檔像素記憶體占用<ARGB*width*height>

來計算,則純像素占記憶體= 4 * 256 * 255 =261120

目前總記憶體大小為:3526656

克隆位圖對象的bitmapData後的總記憶體大小為:3788800

克隆後增加的記憶體大小為:262144

num=1000 || 目前總記憶體大小為:3788800

生成num個位圖并添加到顯示清單中後的總記憶體大小為:4452352

生成num個位圖并添加到顯示清單中後增加的記憶體大小為:663552

花費時間:103毫秒 || 平均操作每個對象需時:0.103

  //----------------------------------------------------------------------------->

  再來看将for中代碼修改為new出一個空bitmap之後,對其bitmapData指派的做法,有沒有不同。

[javascript] view plaincopyprint?

for (j = 0; j < num; j++)   

{  

        tempBMP = new Bitmap();  

        tempBMP.bitmapData = bmp.bitmapData;  

        this.addChild(tempBMP);  

        tempBMP.x = j + 300;  

        tempBMP.y = j;  

}  

  請看輸出:

  //-------------------------------------------------------------------------------->

  載入圖檔前總記憶體大小為:3174400

載入圖檔後總記憶體大小為:3526656

載入後增加的記憶體大小為:352256

loader的總位元組數為:61831

Bitmap的總位元組數為:61831

目前總記憶體大小為:3526656

BitmapData指派後的總記憶體大小為:3526656

copyPixels位圖對象的bitmapData後的總記憶體大小為:3526656

bitmapData.draw()位圖對象後的總記憶體大小為:3526656

new一個Bitmap空對象bmp1後的總記憶體大小為:3526656

對bmp1.bitmapData指派後的總記憶體大小為:3526656

使用得到的bmpData對象生成bmp2後的總記憶體大小為:3526656

将bmp1添加到顯示清單後的總記憶體大小為:3526656

将bmp2添加到顯示清單後的總記憶體大小為:3526656

圖檔寬度=256,高度=255

按PNG圖檔像素記憶體占用<ARGB*width*height>

來計算,則純像素占記憶體= 4 * 256 * 255 =261120

目前總記憶體大小為:3526656

克隆位圖對象的bitmapData後的總記憶體大小為:3788800

克隆後增加的記憶體大小為:262144

num=1000 || 目前總記憶體大小為:3788800

生成num個位圖并添加到顯示清單中後的總記憶體大小為:4456448

生成num個位圖并添加到顯示清單中後增加的記憶體大小為:667648

花費時間:17毫秒 || 平均操作每個對象需時:0.017

  //------------------------------------------------------------------------------->

  我之前試了很多次,這種處理,會比上面一種生成時直接以bitmapData來生成bitmap花費的時間要長一點,記憶體也多一點,不知這次如何,我修改代碼後運作直接把輸出複制過來了,也沒細看。

送出以後看到前一次的輸出,時間好久,喜歡動手的下載下傳下面的RAR檔案自己多測試幾次吧,有時候測試效果不穩定,這很無奈。

下面來看另一種情況,new 出來bitmap後再new 出來一個bitmapData不填充值的對象,然後再利用其CopyPixels函數來處理,在看代碼和效果前,一定明白這樣相當于這個bitmap采用了一張新的位圖,而CopyPixels函數,隻是把另外一張位圖中的資料重新指向過來。看完修改的代碼和輸出後,下面再細說。

[javascript] view plaincopyprint?

for (j = 0; j < num; j++)   

{  

        tempBMP = new Bitmap();  

        tempBMP.bitmapData = new BitmapData(bmp.width, bmp.height);  

        tempBMP.bitmapData.copyPixels(bmp.bitmapData, rect, vertex);  

        this.addChild(tempBMP);  

        tempBMP.x = j + 300;  

        tempBMP.y = j;  

}  

  請看輸出:

  //------------------------------------------------------------------------------------>

  載入圖檔前總記憶體大小為:3174400

載入圖檔後總記憶體大小為:3530752

載入後增加的記憶體大小為:356352

loader的總位元組數為:61831

Bitmap的總位元組數為:61831

目前總記憶體大小為:3530752

BitmapData指派後的總記憶體大小為:3530752

copyPixels位圖對象的bitmapData後的總記憶體大小為:3530752

bitmapData.draw()位圖對象後的總記憶體大小為:3530752

new一個Bitmap空對象bmp1後的總記憶體大小為:3530752

對bmp1.bitmapData指派後的總記憶體大小為:3530752

使用得到的bmpData對象生成bmp2後的總記憶體大小為:3530752

将bmp1添加到顯示清單後的總記憶體大小為:3530752

将bmp2添加到顯示清單後的總記憶體大小為:3530752

圖檔寬度=256,高度=255

按PNG圖檔像素記憶體占用<ARGB*width*height>

來計算,則純像素占記憶體= 4 * 256 * 255 =261120

目前總記憶體大小為:3530752

克隆位圖對象的bitmapData後的總記憶體大小為:3792896

克隆後增加的記憶體大小為:262144

num=1000 || 目前總記憶體大小為:3792896

生成num個位圖并添加到顯示清單中後的總記憶體大小為:266907648

生成num個位圖并添加到顯示清單中後增加的記憶體大小為:263114752

花費時間:1236毫秒 || 平均操作每個對象需時:1.236

  //------------------------------------------------------------------------------------>

  看看上面輸出結果的最後兩行,是不是很讓人驚奇,好大的記憶體增加,以及好長的時間花費,CPU占用還好,我第一次測試時,num=10000,最後超過預設的15秒不響應限制,也沒有出來結果,但CPU占用一直穩定在25%(僅FP,還是在debug模式下),而且作業系統提示虛拟記憶體不足。

從最後一個測試可以看出,我們要盡量少用new BitmapData()這個函數,如果使用了這個函數,基本相當于引入了一張新位圖圖檔。

四、結論和我的猜測

結論将是由以上測試總結出的可驗證的判斷,但我的猜測就不行了,将僅僅是這些結論往前回溯性的猜測,是以可能被我蒙中了,也可能根本就是瞎猜,看到的各位,可以算做抛磚引玉,由此讨論,但不要就此擡扛。

  1、通過前面對CopyPixels函數的測試,可以看到,這個函數是極節省記憶體的。與直接使用一個位圖的bitmapData資料生成一個新的bitmap基本沒有差别。而且速度也很不錯。

//--------------------------------------------------------------->

  num=1000 || 目前總記憶體大小為:3788800

生成num個位圖并添加到顯示清單中後的總記憶體大小為:4452352

生成num個位圖并添加到顯示清單中後增加的記憶體大小為:663552

花費時間:103毫秒 || 平均操作每個對象需時:0.103

  //--------------------------------------------------------------->

  這段輸出是對循環1000次,先給bitmapData指派,再調用CopyPixels的測試輸出,看記憶體的增加與,跟去掉CopyPixels操作之後基本沒有差别。

  2、在使用位圖資源時,盡可能的少用new BitmapData來生成位圖,因為這相當于載入了一張新位圖。

  3、位圖資源無論檔案本身如何壓縮,如何小,但載入記憶體後,其占用的記憶體空間,基本可按<ARGB*width*height>來計算,當然實際結果會比這個數值略大,這可以從測試中的Clon()函數的調用記憶體增加看出。

4、由結論3,可以推導出一個遊戲的flash用戶端中,究竟可以引入多少位圖資源,按照webgame的記憶體占用率一半,CPU等計算資源30%的原則來算占用的最大記憶體,單獨一個web game的記憶體占用量上限可考慮300MB~600MB,以輕量級的web game 上限記憶體300MB來算,那就是1024*1024分辯率的圖檔JPG之類無alpha通道的圖檔100張,PNG格式有alpha通道的圖檔75張,無論是矢量存儲載入後轉位圖,還是直接就是位圖。而這個位圖資源的上限公式,可以作為一個遊戲項目的主策劃用來限制随意策劃的一個測量标尺。參考資料:http://www.shengshiyouxi.com

  //---------------------------------------------------------------------------------------------------------------------->

  以下是我猜測性的推論,請審慎視之

1、從記憶體增量上來看,使用已載入的位圖資源資料來new 出一個新的位圖,應該僅是生成了一個位圖對象,而實際的位圖資料還是指向原始的位圖資源。

2、人為的在代碼中調用垃圾回收機制,既沒必要,也不需要,反而徒增系統資源的浪費。

3、普通對象的引用計數清除很重要,這關系到這些對象占用記憶體的回收。

4、位圖類對象的位圖資料,調用銷毀函數很有必要,在不使用某個位圖資源時,将某個位圖資源手動銷毀,垃圾回收并不起作用。

5、bitmapData相比普通的類對象,要特别一點,特别之處有二,一是該對象引用指向的對象實際資料區,需要手動銷毀才能退出占用的記憶體;另一是對該對象引用指向的實際資料,在進行資料修改,以讓其顯示的位圖有不同的顯示效果時,該修改并不是直接在實際的原始資料上進行修改的。

6、從bitmapData的特别之處,可以看到,流布于一些AS3效率優化文章内的慎用濾鏡等之類的看法,應該也是這個問題的延伸。

繼續閱讀