Home > When garbage collection does more than you want

When garbage collection does more than you want

September 4th, 2009 Leave a comment Go to comments

I had an interesting Flex bug to solve a day before the project deadline. I was showing a progress bar while some images were preloading in the background. The application was only allowed to fire applicationComplete event once these images have finished loading.

The client complained that the progress bar stalls the first time you run the app in the browser. Refreshing the page causes the application to start immediately, as if everything has been loaded. I reproduced the bug with bandwidth throttling. That made me think: “the assets are being fully loaded, but the progress bar doesn’t seem to care”.

With further investigation, I realized that I solved the same problem over a year ago. When one creates Loaders on the fly, such as in a loop, one often does not keep any reference to these Loaders outside of the scope of the function. Since it is a good habit to make event listeners weak, it is possible for the garbage collector to flag these Loaders for removal before they even have a chance to fire their complete event.

So to make sure that the progress bar does not stall, I needed to keep a reference to the Loader that I create within my loop. I simply pushed every Loader to an array. Once everything finished loading and the application started, I cleared the array to allow the garbage collector to take care of the rest.

Problem

Progress bar stalls while preloading images.

Cause

Loaders with weak event listeners and no references to them within the application.

Solution

Use an array to store references to the Loaders until all of them have finished loading.

  1. September 5th, 2009 at 06:42 | #1

    I am not sure of how you instantised this loaders with a loop but there are a couple of options which may work around these issues:

    keep the declaration of that loader outside og the loop:

    var len: int = 5; // or whatever your length is
    var newLoader : loader;
    for(var i : int , i< len, i++){
    newLoader = new Loader();
    //
    }

    Or use a simple loader with the complete event as a protected function and use inheritance to extend this simple loader, use polymorphism and override the function for the complete in this new class. You simply tick through each url and place the contents into an array. You are reusing the same loader as well.

    I should show an example but do you get what I am saying?

    Elliot

  2. September 7th, 2009 at 18:15 | #2

    Even if you keep the declaration outside of the loop, the garbage collector might pick up everything except the last loader. Every iteration, you remove the reference to the previous loader, thus enabling it to be removed from memory. Reusing the loader variable has proven unreliable in my projects.

  3. Victor
    September 24th, 2009 at 05:40 | #3

    I disagree it’s a good habit to use weak listeners references.

    I thought that for a while, but I have come to the conclusion that it is much better to get used to remove the listeners when it’s appropriate.

    If you use weak listeners, you will continue to receive notifications sometimes, and sometimes not, depending on the whim of the garbage collector. Bad idea. It’s better to always receive the event, so that it reminds you of removing the listener.

    I think that I thought that because I didn’t realized that when A points to B and B points to A, and no one of both points to any other external object, then both will get collected.

  4. Daniel
    November 2nd, 2009 at 15:26 | #4

    When garbage collection does LESS than you want:
    I was creating a new object every second and deleting another one so I only had 8 at any one time..
    Flash’s memory went up and up and up till 200MB and the fps went down to 0!

    Instead I stored an array of ones I had pre-made and GC comes along when I destroy everything! Bad hack but it’s the only way round it.

  1. No trackbacks yet.