I'm creating an asteroids game and in my main class I'm having some trouble handling the bullets that the ship fires.
All of the bullets are of the "Bullet" class and are stored in an array called "bullets" in the main class. When bullets exit the screen, removeBullet(bulletID) in the main class is called.
private function removeBullet(id:int)
开发者_高级运维 {
removeChild(bullets[id]);
bullets.splice(id);
}
In my Bullet class I have an enterFrame listener that traces "stillHere". So as soon as a bullet is added to the main stage using addChild, "stillHere" starts popping up in my output panel.
My problem is that even after I call the removeBullet, "stillHere" keeps popping up in the output panel, which tells me that the object which I tried to delete is still sticking around somewhere in the memory.
What can I do to get rid of it completely?
Because you are in ActionScript you have no direct control over when objects get removed.
The real problem you have is that your event listeners are still firing. You can obviously solve this by calling removeEventListener
when they are deleted.
However a better approach is to have just one ENTER_FRAME
listener for the whole game. It will need to individually advance all the game elements (ship, asteroids, bullets, debris etc). This method removes any chances of you accidentally forgetting to remove event listeners, and it also makes the code clearer since you can see the order that elements will update within a time step.
I usually have a destroy
function in my temporary objects which reads something like this:
public function destroy():void {
stop(); // if it's a MovieClip
if(parent) parent.removeChild(this);
}
As long as I call this function and then remove references to the object, it's usually collected.
My code very rarely has listeners on individual objects for this reason.
The event listener itself could very well be the reason it's still in memory. That is not a good way to test whether something has been garbage collected or not.
Also, even if that were a good way to check whether an object has been garbage collected, collection is not an instantaneous process. The Flash Player will only run the gc when it needs to allocate more memory and fails to do so.
Assuming you have no other references to the bullet object besides the display list and the bullets array, what you've done is sufficient to allow it to be garbage collected.
EDIT : To answer the question as to whether there's any way to observe whether an object has been collected...
You can use the object as the key in a weakly keyed dictionary.
private var _dict:Dictionary = new Dictionary(true);
_dict[bullet] = "Bullet is still here...";
Then whenever you want to check whether the bullet still exists, you use a for...in loop to iterate the keys
for(var key:* in _dict){
trace(key + " " + _dict[key]);
}
Because a weakly keyed dictionary's keys do not count as references for the purposes of garbage collection, this works.
If you're very concerned about memory leaks, you might consider writing an object pool into which you place old bullet objects that you remove from the stage, and simply re-use them over and over. In this way you'll never allow any bullets to be garbage collected, but you'll probably only ever create a small, limited number of bullets (that being the number of bullets the user ever sees onscreen simultaneously at a given time). This might be the best solution for you as the bullets probably have a small memory footprint and you get the bonus of not forcing Flash to clean up your garbage. Running the GC causes performance degradation while the garbage is being removed, so by that measure doing what you can to prevent even needing it is a good thing.
精彩评论