A Flash Developer Resource Site

Results 1 to 15 of 15

Thread: [Disc] Garbage collection in AS3, methods and techniques.

  1. #1
    Senior Member AzraelKans's Avatar
    Join Date
    May 2002
    Location
    Hell... with frequent access to heaven ;)
    Posts
    409

    [Disc] Garbage collection in AS3, methods and techniques.

    I'm opening this thread in Garbage Collection techniques for AS 3.0, hoping it will become a sticky for those who are working with AS 3.0

    This is the issue:As you may know AS 3.0 doesn't have the AttachMovieClip, CreateEmptyMovieClip or DuplicateMovieClip commands, instead you need to create a new instance of either a MovieClip, Bitmap or Sprite class (or an inherited class based on one of those) and then add this Instance to the display list via the addChild command. The process is fairly straight forward:

    Code:
    (pseudocode may have syntax errors)
    
    var myClip:MovieClip=new MovieClip()
    addChild(myClip)
    
    //Adds an empty MovieClip to the display list (to the screen)
    Also since _root no longer exists theres no way to keep track of your new instance unless you keep the Original MovieClip pointer (that is in our case the MyClip variable) or add it to an array, a list or just about any variable that can Hold a MovieClip pointer.

    Code:
    var MyClipArray=new Array()
    MyClipArray.push(myClip);
    You can also assign an Event to that movieClip like enterFrame

    Code:
    MyClip.addEventListener(events.EnterFrame,tick)
    
    function tick(e:Event){
     trace("Im Still Alive!")
    }
    Now you can apparently delete a movieClip, Bitmap, Sprite by Simply removing it from the screen

    Code:
    var i:String
    for (i in MyClipArray){
        removeChild(MyClipArray[i])
    }
    However if you do this example, you will still see the message

    "Im Still Alive!"

    Even if the MovieClip object has been removed.


    The problem is the new VM in as 3.0 (like Java) does NOT perform automatic Garbage Collection, so removeChild WILL NOT remove the Clip from memory, or remove the eventlistener, therefore the MovieClip is in fact, "still alive" (going to an empty frame the main timeline,(gotoAndStop method) wont work either. since the GD isnt automatic there either)

    So you will still keep seeing the trace message.

    "Im Still alive!"

    Until you close the application or the browser window. However you don't have access to the child anymore.

    Of course, this can be a performance nightmare, if you create per example 100 particles in an enterFrame tick, "destroy them" and then add another hundred in the next, your performance may drop within minutes or even seconds. (depending on the nature of your particles)

    Now afaik there are 3 known methods to deal with this.


    1.-Use and Reuse your current objects.
    I know, is not the most elegant method but it works, simply use the instance objects you already have on the screen, or create a limited number of objects (enemies per example) and reuse them as needed, it may sound silly but reusing objects is a technique gamedevs have been using for decades when they have to deal with memory issues and the results are good enough for small-medium projects and the like. (also this can be used in combination with method 3 keep reading)

    2.-Carefully use AS3 garbage collection

    Gargabe collection does work, but is not automatic, in our example we'd need to use removeEventListener, then removeChild to stop the event from ticking, however this WONT immediately destroy the object until the Garbage Collector kicks in.

    Also if the object is a MovieClip you can try adding an Empty Frame then use gotoAndStop(emptyFrame), The object is still there in memory until the gc decides otherwise, but at least it wont bother us anymore.

    Code:
    var i:String
    for (i in MyClipArray){
        myClipArray[i].removeEventListener(Event.ENTER_FRAME)
        removeChild(MyClipArray[i])
    }
    If you had added timers, listeners, references or any other link to it then you will have to remove it by hand as well.

    note: Your performance mileage may vary using this method. Memory Leaks May occur if you are not careful enough.


    3.-Use Bitmaps instead.
    The method most professional AS 3.0 game developers are using. Pixel based bitmap Methods in as 3.0 are up to 10 times faster than their AS 2.0 Bitmap counterparts, so is now possible to use bitmaps to render our objects in AS 3.0 at pretty decent speeds, of course you will need to handle all the processing, updating and rendering of the game objects by your self, but the performance (if you are careful) may just be worth it. (besides is a nice change to use bitmap based games on flash at pretty decent speeds, depending on your screen size and optimization)

    -Reusing MovieClips part2: another trick you can use, is to create single instances of movieclips and then use the bitmap.draw(movieClip) to render them on a bitmap screen instead of addChild. Difference is, a single MovieClip can represent hundreds of objects in the screen just like a bitmap.

    note: This is not recommended if your game still depends heavily on Vector based MovieClips, or needs scaling, use prior methods instead.

    So thats it, the discussion is open, please correct any errors I may (and probably did) committed in the explanation and feel free to add any method you recommend or use to deal with this problem.
    Last edited by AzraelKans; 01-18-2008 at 02:52 PM.

  2. #2
    Senior Member tonypa's Avatar
    Join Date
    Jul 2001
    Location
    Estonia
    Posts
    8,223
    I dont think Movie Clips are any good for AS3, bitmaps are much better. And less objects performs better so basically 1 big bitmap covering whole stage which you update when needed. Or if you like vector graphics, use Shape object. If you need interactive content, use Sprite. While Movie Clips still exist, there is really no need for them, just like Buttons. If you rely heavily animations within Movie Clips, AS2 may suit better.

    Basic setup for any game still remains similar - keep the game controlling code in one place (just like it is not recommended to spread code over frames in AS1/2) so your main class can handle the events, listeners and display.

  3. #3
    Heli Attack! iopred's Avatar
    Join Date
    Jun 2003
    Location
    Sydney, Australia
    Posts
    923
    This problem can be completely ignored if you create Weak Referenced event listeners:

    eventDispatched.addEventListener(event, function, false, 0, true /*THIS TRUE IS IMPORTANT */);

    The final true makes sure that the event listener does not keep a strong link to the object. Meaning if its the last thing that is still referencing that object, the garbage collector will ignore the weak link, and remove the object.
    Last edited by iopred; 01-19-2008 at 07:46 AM.
    Christopher Rhodes
    squarecircleco.

  4. #4
    Hype over content... Squize's Avatar
    Join Date
    Apr 2001
    Location
    Lost forever in a happy crowd...
    Posts
    5,926
    Cool tip mate.

    Perhaps it's just me, but I really don't get all the fuss about the new GC.

    If you attach a listener to a sprite / mc, then you should remove it as well. It's just lazy coding to expect the old school mc.removeMovie(); to tidy up all the other stuff for you too.
    Even in pre-as3 you still had to do that. If you load a swf into another one, and the child swf has a setInterval then the child swf has to stop that setInterval even if you unload it or remove it via the parent swf.

    For whatever you create in a game there should be a houseKeeping method which cleans it up, otherwise you're going to have memory leaks and it's going to affect performance.

    Going back to the actual GC, as I understand it when it kicks in it can stall the Flash Player for a frame or two ( As it's clearing all the crap in one hit ) ?
    I guess the delay is due to the number of objects it's got to destroy, as recycling objects doesn't seem to cause any kind of GC hit.

    So how many objects does it have to be ? Does clearing say 32 objects cause a hit ? 320 ? 3200 ? ( I'm not being flippant, I really don't know as I recycle objects ).
    Off the top of my head I can't think of any games where you can't recycle any created object if the structure is sound.

    Being honest I am a newbie when it comes to as3, I've not finished my first game using it yet, but it seems like the whole GC thing has been blown out of proportion considering the number of posts and complaints about it.
    Azrael I'm not having a dig at you, but I guess the importance of it is just passing me by.

    Squize.

  5. #5
    Yes we can tomsamson's Avatar
    Join Date
    Sep 2001
    Location
    Team Titan Secret Lair
    Posts
    4,666
    Sure you can reuse stuff, but the more you pregenerate and reuse the more ram you use.
    And sure one can create weak references and do housekeeping and generally with such structured app sturcture have few to no issues with GC.

    To speak just about me: I moan so much about the GC and AS3 and generally newer things flash because in my eyes Adobe is heading towards the wrong direction there.

    It was reasonable to not support 3d card features several years back.
    To now support multi threading and multi cores but still no 3d card features has the opposite effect though, only people with high end systems (or cpus) can run high end flash content smoothly.

    Same can be said about ram usage, when you think about it with reusing everything and pregenerating lots of spirtesheets and what not all you´re reducing the cpu heap on one end but raising the ram heap a lot on the other end.

    As general moan point Macromedia/Adobe hasn´t achieved to significantly improve the performance of the player in the past few years (if you´re happy with AS3 performance compare it with the one of Java or better C#), in return they force developers to work in more and more oop manner and a stricter and stricter syntax and compiler and take care of things that should be taken for granted and do things in low level manner like by dealing with bitmapdata codeside manipulation and bytearray doodling if they really want hafway acceptable performance stuff.

    Its nice that such new possibilities are added, its ugly that one is forced to do things in certain way because flash isn´t up to it when doing it in higher level manner.

    Also: yeah, i can code in oop manner and have done it for a good while, but the closer flash is getting to java and C# in the language and the way in which you have to do things, the more i wonder why i should use flash with its way way worse performance and tons of other issues.

    The one remaining plus is the dominance of the plugin and even that could change rather quickly in the web world.

    So yeah, i don´t want to totally downtalk flash, but in my eyes adobe better gets its act together for flash 10.
    Last edited by tomsamson; 01-19-2008 at 12:29 PM.

  6. #6
    Senior Member webgeek's Avatar
    Join Date
    Sep 2000
    Posts
    1,352
    I dont think Movie Clips are any good for AS3, bitmaps are much better. And less objects performs better so basically 1 big bitmap covering whole stage which you update when needed.
    I don't have anything I can show off yet, but our latest engine involved several rounds of testing to come to this same conclusion. You will consistently get the best performance if you can draw everything to a single bitmap on the screen. We played with double buffering as well but in the end, single bitmap won out. This even includes animating objects. In our latest project, movie clips have simply become a way to store the frames of an animation. We copy everything out into single bitmaps for actual rendering.

  7. #7
    Yes we can tomsamson's Avatar
    Join Date
    Sep 2001
    Location
    Team Titan Secret Lair
    Posts
    4,666
    yup,same here for as3 stuff.

  8. #8
    Senior Member tonypa's Avatar
    Join Date
    Jul 2001
    Location
    Estonia
    Posts
    8,223
    Quote Originally Posted by Squize
    Going back to the actual GC, as I understand it when it kicks in it can stall the Flash Player for a frame or two? I guess the delay is due to the number of objects it's got to destroy, as recycling objects doesn't seem to cause any kind of GC hit.

    So how many objects does it have to be ? Does clearing say 32 objects cause a hit ? 320 ? 3200 ?
    Well, as I understand it, GC has to check all the objects you are using and find the ones not being referenced anymore. Its not that bad if every object was created and deleted by one single main object but it can get complicated if the objects cross-reference each other.

    Then again, it may depend on total memory usage. GC does not even bother to start cleaning if your game does not use up enough memory. Memory is eaten mostly by bitmaps (and sounds perhaps) so if there are loads of them GC probably needs to do he checks more often.

    Interestingly I read somewhere total memory is calculated for all Flash movies playing in the browser, if there are other swfs in same page, in other window or tab, they all count up into single value. As designer has no control over how many tabs in the browser user has opened or what content is shown, one badly designed swf can ruin every Flash content. This has of course been in theory same even for pre-AS3 content, but seeing how easy it is to make bad AS3 swf, I suspect we can expect for example Flash ads mess up many games. You could debug your game forever and it can still randomly crach if there is bad ad somewhere on the page shown at 1/100 rate.

  9. #9
    Hype over content... Squize's Avatar
    Join Date
    Apr 2001
    Location
    Lost forever in a happy crowd...
    Posts
    5,926
    Oh, I didn't think it'd loop through every object, I just imagined that once you used delete object; it was shoved onto an internal stack and then when the GC kicked in it just worked with that list ( And the delay being the sheer number of objects in that list, and having to check to see if there are any references left to them, ie if they can be deleted or not ).

    Squize.

  10. #10
    Senior Member AzraelKans's Avatar
    Join Date
    May 2002
    Location
    Hell... with frequent access to heaven ;)
    Posts
    409
    Wow great comments and tips, I really didnt knew about the weak referencing with Events, that can really be useful, And Squize is right, setInterval has always need to be manually released and that has never been adressed as an issue. (although is not the same thing to remove a timer, than an entire movieclip)

    TomSanson
    Sure you can reuse stuff, but the more you pregenerate and reuse the more ram you use.
    Hmm, why? What I meant By reusing movieclips, is that you create one movieclip, and then use the same clip again to display a different frame (which could a different, enemy, tile, etc) I dont see why you need more memory. If you are using the same movieclip.

  11. #11
    Senior Member
    Join Date
    Jul 2008
    Posts
    418
    i'd guess, he meant because then sometimes you dont use movieClips, that are in the memory, being saved for later.

  12. #12
    FK founder & general loiterer Flashkit's Avatar
    Join Date
    Feb 2000
    Location
    Sydney
    Posts
    1,149
    that trick about rendering all to the same bitmap is gold, thanks for that. I just tried that in my car game and its made things very smooth indeed!
    Regards Mark Fennell - Flash Kit Founder, general loiterer
    -------------------------------
    I Hate Zombies - iPhone Game | markfennell.com

  13. #13
    Knows where you live
    Join Date
    Oct 2004
    Posts
    944
    None of your examples represent any failure of the garbage collector. As a matter of fact, they are the correct and logical behavior.

    I think the real problem is that people don't understand that the display list is just simple code, it is not a built in part of the VM and does not have any special powers (aside from drawing).

    In the first place, I have no idea why anyone would assume that tying the graphical representation and the code together like this would be a good idea. (Why in the world should the visibility of an object determine if its code is executed?) Secondly, it would create many contradictions in how objects are managed and would completely separate the display hierarchy from normal code.

    Lets start with your example code:
    Code:
    var myClip:MovieClip=new MovieClip();
    MyClip.addEventListener(Event.SomeEvent,doSomething);
    addChild(myClip);
    This is pretty clear, the movieclip with a listener is added to the stage.

    Now lets compare it to this code which is logically the same but using my own event system:
    Code:
    myClip = new MovieClip();
    addChild(myClip);
    //Event
    myEventTarget = myClip; // Adding myClip as a listener
    function callEvent () {
        myEventTarget.doSomething();
    }
    What is happening here is that instead of just using addEventListener, I am manually holding a reference to the movieClip and allowing the event to be called by using callEvent as opposed to dispatchEvent. I think this is where some of the confusion comes from. Events are not some magic part of the virtual machine, they work in a similar manner to what I have done.


    Now lets continue to where you start running into problems:
    Code:
    var myClip:MovieClip=new MovieClip();
    MyClip.addEventListener(Event.SomeEvent,doSomething);
    addChild(myClip);
    removeChild(myClip);
    You believe that as well as simply removing the movieclip from its parent, it should destroy all the events referencing it and just kill the movieclip as well for good measure. What happens if I still want the movieClip? What happens if I was just trying to move it into a different object? There are plenty of valid reasons why I could remove the movie clip from the stage but still want its events to remain valid.

    Code:
    myClip = new MovieClip();
    addChild(myClip);
    //Event
    myEventTarget = myClip; // Adding myClip as a listener
    function callEvent () {
        myEventTarget.doSomething();
    }
    removeChild(myClip);
    By your logic, as soon as I call removeChild, suddenly all code that uses the movieclip becomes broken. Garbage collecting the movieclip would require setting every variable that references it to null. I can assure you that if this were the case people would be having far, far more problems than not cleaning up after themselves. I assure you that I would not be amused if the display list could go around nullifying my variables.

    The crux of the matter is that the display list is not magical, it is simply a run of the mill tree datastructure. The DisplayList has absolutely no business deleting things behind your back, especially when there are plenty of reasons why you would still want to use them.

    The DisplayList is a data structure, not the virtual machine. Logically, DisplayList.removeChild() is absolutely identical to Array.remove() and to suggest that Array.remove() should delete the object in question is laughable.
    The greatest pleasure in life is doing what people say you cannot do.
    - Walter Bagehot
    The height of cleverness is to be able to conceal it.
    - Francois de La Rochefoucauld

  14. #14
    Senior Member
    Join Date
    May 2006
    Location
    Manhattan
    Posts
    246
    totally. i think you've really hit the nail on the head. the display list isn't magic! it's hard to verbalize an off-handed sensation like that- especially when it doesn't make any logical sense to you, but seriously, that's exactly it!

    this reminds me of a member a while ago who got all salty balls with me for saying that it was the developer's responsibility to clear references. he quoted some issue involving MovieClips being impossible to have garbage collected. which of course doesn't sound right, but not ever working with MovieClips, or the desire to work with them, i didn't have a good argument. i don't remember what, if anything, was proven, but it always irked me that i let one of those "as1 forevs", "display list is magic" guys hush me up.

  15. #15
    Funkalicious TOdorus's Avatar
    Join Date
    Nov 2006
    Location
    Nijmegen, Netherlands
    Posts
    697
    That's actually kind of funny. I couldn't grasp the problem until you defined it like that 691175002. I always saw an object and a graphical representation of it as seperate, so I read through AzraelKans post without understanding it. Explain a fish what air is like

    But that's a weird way of looking at it. When I coded in AS2 every player/enemy object had a Graph instance variable in it. The graph could be initted and removed, but the actual enemy or player still existed. Why should I render the movieclip when it's offscreen for instance? Just check if the unit is onscreen and init/remove/relocate the movieclip as necessary.

    The same can be done in AS3, but the add and removechild makes it so much easier, as you can actually update your graphical representations x and y properties without the need of it bieng in the displaylist. Migrating to using prerendered spritesheets and copypixeling the bitmapdata's to the one big bitmap on the screen has simplified this concept even more. Is it onscreen? Paste it. No need to check if the child is added or not.

    More on topic:

    I find the garbage collecter still to be something magical. When I was implementing pooling for the first time, I didn't code it properly and the objects were never actually moved back to the pool. This created a huge data leak, as every object stayed in virtualmachine without bieng used. How this leak manifests itself is still quite odd to me, hence the magical part.

    I found my framerate dropping over time, untill it must have been below .5 a second. Monitoring my system resources I found no built-up in cpu usage, but a huge built-up in memory usage. The number of objects used memory, but the garbage collector did not use more cpu than it would with only a few objects. The reason I find this odd, is that only one of my four cores was burdened by the flash, and the other three were not bieng used. I've seen my flashes using multiple cores on my machine, so it Can use multiple cores.

    What keeps me bewildered is : why would Flash opt to lower the framerate instead of using more cpu to keep the gc going? It seems that the amount of objects/frame the gc can collect is limited then, as only a certain amount of processing power is reserved voor garbage collection.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center