Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AS3 passing a function as a parameter creates memory leaks

I have a function that takes another function as a parameter. Something like this :

public function onHits(target : Shape, callback : Function) : void

I use it by passing a member function as a parameter that should be called whenever the passed target hits something. The function is called many times a frame. So it is used by doing :

//code...
CollisionManager.onHits(myShape, onHitCB);
//code...

The on hit function :

public function onHitCB(hitObject : *) : void 
{
    //removed all code to test this problem
}

When I do this, I have a memory leak. I've isolated the problem to that onHits method and have commented out everything else. onHits is an empty method with no code inside it, onHitCB is also empty. If I comment out the call to onHits, there is no memory leak and if I pass null instead of onHitCB there is no memory leak.

So it's clearly when I pass onHitCB as a parameter that's the problem. So I thought it might be because Flash allocates some memory to create the Function pointer and doesn't release it but I call System.gc() every frame in debug mode and the leak is still there. Which would mean that this is either a bug in the SDK or I'm not doing something right.

I have found a weird workaround by keeping a variable that points to the function which I assign in the constructor of my object :

private var func : Function;

public function MyObject() 
{
    func = onHitCB;
}

and this will clear the memory leak even if I still pass onHitCB as the parameter. So that would mean that it's not the "getter" function to obtain the onHitCB but something else causing the memory leak?

I'm very confused. How can this cause a memory leak :

public function MyObject() 
{
}

public function update() : void
{
    CollisionManager.onHits(myShape, onHitCB);//empty function
}

public function onHitCB(hitObject : *) : void 
{
    //removed all code to test this problem
}

but not this? :

private var func : Function;
public function MyObject() 
{
    func = onHitCB;
}

public function update() : void
{
    CollisionManager.onHits(myShape, onHitCB);//empty function
}

public function onHitCB(hitObject : *) : void 
{
    //removed all code to test this problem
}

and is there a way to not have to do this workaround?

like image 417
Godfather Avatar asked Sep 06 '11 08:09

Godfather


1 Answers

[...] bound methods are automatically created when you pass a method as a parameter. Bound methods ensure that the this keyword always references the object or class in which a method is defined. Source

That sounds like creating a reference to a method isn't using a simple getter. A new method closure object is generated. So your assumption is right.

I wonder why the references aren't cached for each instance and why they aren't garbage collected though. Better avoid creating multiple references. Referencing a method only once is exactly what I would do when I would have to use that method in multiple places, so most of the time I wouldn't call it a workaround but a good DRY practice. In your example it makes sense of course, assuming a method reference would be using a simple getter.

like image 133
kapex Avatar answered Oct 16 '22 01:10

kapex