away3d/away3d-core-fp11 — Issue #157: Dictionaries hanging on to BitmapData instances in BitmapDataTextureCache
Author: jamieowen
Created: 2011-10-18 15:14:31+00:00
State: open

Hi,

I seem to run into some memory problems using BitmapMaterials.

I have narrowed down the cause to the
away3d.core.managers.BitmapDataTextureCache class. But the fix is
just a change to two Dictionaries that are not using weak keys.

Basically the two Dictionaries hang on to BitmapData instances when
you update a BitmapMaterial's bitmapData property directly. You can
confirm this in the Flex Profiler with this basic setup:

package
{
import away3d.containers.View3D;
import away3d.materials.BitmapMaterial;
import away3d.primitives.Plane;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.geom.Vector3D;
import flash.utils.Timer;

public class Main extends Sprite
{
[Embed(source="kt_sheet1.png")]
public static const BITMAP:Class;
public var view3D:View3D;
public var plane:Plane;
public var material:BitmapMaterial;
public function Main()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align =StageAlign.TOP_LEFT;

view3D = new View3D();
addChild( view3D );

addEventListener( Event.ENTER_FRAME, onEnterFrame );
var timer:Timer = new Timer(100,1000);
timer.addEventListener( TimerEvent.TIMER, updateMaterialBitmapData );
timer.start();

material = new BitmapMaterial(( new BITMAP() as Bitmap ).bitmapData);
plane = new Plane(material);
view3D.scene.addChild( plane );

view3D.camera.z = -500;
view3D.camera.lookAt(new Vector3D() );
}
private function updateMaterialBitmapData($event:TimerEvent):void
{
// setting the bitmapdata to null and then updating the bitmap again results
// in the BitmapDataTextureCache hanging on to the instance.

material.bitmapData = null;
material.bitmapData = ( new BITMAP() as Bitmap ).bitmapData;
}
private function onEnterFrame( $event:Event ):void
{
view3D.render();
}
}
}

If you run this in the profiler you'll see the memory collect. Then
comparing two memory snapshots and checking loitering objects shows
the bitmap data are not being cleared from these dictionaries in
BitmapDataTextureCache :

public function BitmapDataTextureCache(singletonEnforcer : SingletonEnforcer)
{
if (!singletonEnforcer) throw new Error("Cannot instantiate a singleton class. Use static getInstance instead.");
_textures = new Dictionary();
_usages = new Dictionary()
}

Passing true to the two dictionaries fixes the problem.
As would deleting the key reference in the freeTexture() method.

Perhaps I shouldn't update a BitmapMaterials bitmapData instance like
this. But the problem came about when i implemented a Factory pattern with
reusable Plane and material objects. Updating a bitmapMaterial object like this seems the like the easiest way to do it.

Cheers
Jamie