Acknowledged

Out Of Memory error and Garbage Collector logic

I've got a watch face with following simplified code: 

class RunOrelView extends WatchUi.WatchFace {
    var logoToDraw;
    
    function onLayout(dc as Dc) as Void {
        logoToDraw = WatchUi.loadResource(Rez.Drawables.Bitmap1);
    }
    
    function onUpdate(dc as Dc) as Void {
        // take another bitmap if some condition met
        logoToDraw = WatchUi.loadResource(Rez.Drawables.Bitmap2);
    }
}

For the old devices with very limited that can store only one bitmap in memory, we'll get Out Of Memory exception on line 10 because the previous bitmap resource wasn't released.

Now let's change this:

logoToDraw = WatchUi.loadResource(Rez.Drawables.Bitmap2);

to this:

logoToDraw = null;
logoToDraw = WatchUi.loadResource(Rez.Drawables.Bitmap2);

and now everything works fine with no exceptions. Because we've freed resources manually? Why compiler can't do "logoToDraw = null;" by itself when I do variable assignments? 

  • Right, I meant that it won’t be released in the first case because app will fail with OOM error. And I assume compiler can do “variable = null” everywhere where it sees variable assignment. Or have more smart algorithm but with this kind of approach 

    The compiler absolutely does reference counting and it does free memory when there are no more reference to a given object, but the implementation might not be optimal.

    What I'm saying that in the first case, I think memory would be released, but it's too late to avoid the out of memory error. I'm saying that the memory would probably be released *after* loadResource() is executed but before its value is reassigned to logoToDraw, meaning that there's a point in time where 2 bitmaps are resident in memory.

    In other words, imagine that the actual sequence of events looks like this (roughly speaking).

    1st case

    Your code:

    logoToDraw = WatchUi.loadResource(Rez.Drawables.Bitmap2);

    What probably happens:

    tmpVar = watchUi.loadResource(Rez.Drawables.Bitmap2); // at this point, 2 bitmaps are resident in memory (logoToDraw and tmpVar) which could lead to OOM
    // previous value of logoToDraw is freed immediately before reassigning logoToDraw
    logoToDraw = tmpVar;

    2nd case

    Your code:

    logoToDraw = null;
    logoToDraw = WatchUi.loadResource(Rez.Drawables.Bitmap2);
    What probably happens

    logoToDraw = null; // previous value of logoToDraw is freed immediately, since you explicitly assigned it to null
    tmpVar = watchUi.loadResource(Rez.Drawables.Bitmap2)
    logoToDraw = tmpVar;

    Again, it might be possible for you to verify my speculation by generating debug output for each of those cases.

  • Right, I meant that it won’t be released in the first case because app will fail with OOM error. And I assume compiler can do “variable = null” everywhere where it sees variable assignment. Or have more smart algorithm but with this kind of approach 

  • I would speculate that in the first case, the previous value of logoToDraw is only freed *after* WatchUi.loadResource() is executed (but before its result is assigned to logoToDraw, obviously).

    You might be able to verify that by using the "-g" compiler option and examining the generated instructions in each case.