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? 

  • I simplified my explanation for sure. Usually compilers have some level of how deep they go for analysis. In this case it would be nice:

    1. if the compiler can’t find variable usage in the right side of expression - improve the way I suggested.
    2. If the level of analysis is not enough OR if it finds variable usage - keep behaviour as it is.

    I might cover 80% of cases. Please correct me if I’m wrong

  • My suggestion is to improve compiler the way it release previous object before calculating (or load any resources) that placed after assigning sigh „=“. Like to perform the same as developers need to do now to avoid OOM. 

    I thought about this problem a bit more and maybe it's not so clear cut.

    Consider this code.

    var obj = new SomeExpensiveClass(); // line 1
    obj = SomeExpensiveClass.clone(obj); // line 2

    Obviously obj can't be reassigned to null between line 1 and line 2 as you suggest since the new value depends on the old value.

    So you'd have to have a rule that looks something like this:

    - When encountering a statement such as "x = [some expression]"...

    - ...the compiler should behave in a way that's equivalent to inserting "x = null" immediately before the current statement...

    - ...unless "[some expression]" contains x.

    I can see why the current behavior is what it is.

    Here's another case to consider:

    var global_obj = new SomeExpensiveClass();
    function reassignGlobalObj() {
      global_obj = calculateSomeExpensiveClass(); // global_obj does not explicitly appear in the RHS, so hypothetically the compiler can insert "global_obj = null" above
    }

    function calculateSomeExpensiveClass() {
      var new_global_obj = new SomeExpensiveClass();
      new_global_obj.someMember = global_obj.someMember;
      return new_global_obj;
    }

    In this case, it's a lot harder to modify the rule to cover this case. Anyone who tried to formulate such a rule would have to somehow prove that there are no edge cases which break the rule. What if the RHS calls some library function or system function whose implementation is opaque to the compiler?

    Seems a lot easier to go with the current behavior:

    - given the statement: x = RHS

    - ...x is not reassigned until RHS is evaluated

  • But I agreed with you and I didn’t say it works in a different way. I just pointed that it won’t be released because OOM happens before this. If we have enough memory the object will be released ofc. My suggestion is to improve compiler the way it release previous object before calculating (or load any resources) that placed after assigning sigh „=“. Like to perform the same as developers need to do now to avoid OOM. 

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

    Except ofc you would want to do it with a smaller example that doesn't lead to OOM haha.