2
votes

This is simple test on AS3 for BitmapData memory allocation.

private function memoryTest(): void
{
  trace("BitmapData memory test. Create bmps..."); // First breakpoint
  var bmps:Array = new Array (1000);

  for (var i:int=0; i<1000; i++)
  {
    bmps[i] = new BitmapData(451, 451, true, 0);
    trace(i+". bmp created");
  }

  trace("All bmps created."); // Second breakpoint

  for (i=0; i<1000; i++)
  {
    bmps[i].dispose();
    bmps[i] = null;
  }
  bmps.splice(0, bmps.length);
  bmps = null;

  freeMemoryGC();

  trace("All bmps deleted.");
  trace("Test complete."); // Last breakpoint
}

private function freeMemoryGC(): void
{
  // the GC will perform a full mark/sweep on the second call.
  try
  {
    new LocalConnection().connect('foo');
    new LocalConnection().connect('foo');
  }
  catch (e:*)
  {
  }

  System.gc();
  System.gc();
}

There are 3 breakpoints in this test, that are commented in code. Breakpoints pause program during some time. Breakpoints correspond to the horizontal lines on this memory state chart.

memory usage graph

My question is: why not all memory was free after dispose() calls? What wrong in this code and how to clear BitmapData objects properly?

UPDATE 1: I don't think that problem is in garbage collector. dispose() works out of GC and it should release the pixels data. Also this example should allocate 451*451*4*1000 bytes theoretically. But this test application allocates 25% more bytes in System.privateMemory and these 25% is never released by GC and dispose().

UPDATE 2: If I create 13 images 4059x4059 px instead of 100 images 451x451 px, then memory allocates exactly equals to theoretical size and memory is released properly after call GC! I don't know why it happens.

UPDATE3: Here is my results of interval test, created by Daniel MesSer in him answer: memory usage graph on interval test

1
Run this test 100x times and than check . I suggest You to make interval and run this on each frame . Calling GC doesnt mean that memory will back to same state . - turbosqel
Interesting idea about 100x times and interval. - Eugene
How are you calling memoryTest()? Is there anything outside of that function that is allocating memory? - NoobsArePeople2
You have result of inverval checking ? If memory is instantly growing , this mean that You have leak , if not , everything is fine . Do not focus on few kb leak . - turbosqel
I think the extra 25% might account for the internal mipmaps that are being creaated. - Quasimondo

1 Answers

0
votes

Try and remove the thing about local connection in free memorygc-function. Does that solve it?

EDIT:

package nyx_gaming_group.as3_tests {
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.system.System;
import messer_entertainment.MesSerUtils;

/**
 * ...
 * @author Daniel Dahlkvist
 */
public class BitmapDataMemoryLeak extends Sprite {
    private var _bitmaps:Array;

    public function BitmapDataMemoryLeak() {
        run();
    }

    private function run():void {
        MesSerUtils.delayCall(createBitmaps, 150);
        MesSerUtils.delayCall(destroyBitmaps, 4500);
        MesSerUtils.delayCall(freeMemoryGC, 4700);
        MesSerUtils.delayCall(run, 8000);
    }

    private function createBitmaps():void {
        trace("BitmapData memory test. Create bmps..."); // First breakpoint
        _bitmaps = new Array(1000);

        for (var i:int = 0; i < 1000; i++) {
            _bitmaps[i] = new BitmapData(451, 451, true, 0);
        }

        trace("All bmps created."); // Second breakpoint            
    }

    private function destroyBitmaps():void {
        for (var i:int = 0; i < _bitmaps.length; i++) {
            _bitmaps[i].dispose();
            _bitmaps[i] = null;
        }
        _bitmaps = null;

        trace("All bmps deleted.");
        trace("Test complete."); // Last breakpoint
    }

    private function freeMemoryGC():void {
        System.gc();
    }
}
}