Out of memory (to many layouts in DF?)

Hi, I'm building a complex data field that uses layouts. I currently have 7 different layouts defined in my layouts.xml file (to handle different devices and field obscures). When I run the DF in my SIM I get this in my console:

Error: Out Of Memory Error
Details: Failed invoking <symbol>
Stack:
- MainLayout() at Rez:40 0x10001b3f
- onLayout() at  

 This happens when I test multiple field layouts in the SIM. 

if I remove one of my layouts (having only 6 different layouts) in the layouts.xml file the problem disappears. 

I understand it may be a simulation problem only since you typically cannot run the same DF on multiple fields on the same "screen" on the device, but it would be very helpful to be able to test all field layouts in the sim. 

 Is there a known memory limitation in the Simulator, or am I doing something wrong with my layouts?

Layouts.xml:

<layouts>
    
    <!-- A generic, centered layout. -->
    <layout id="MainLayout">
        <drawable class="Background" />
        <bitmap id="img" x="dc.getWidth()/2 + 25" y="dc.getHeight()/2" filename="../drawables/None.png" />
        <label id="label" x="center" y="3" color="Graphics.COLOR_LT_GRAY" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
        <label id="value" x="dc.getWidth()/2+20" y="dc.getHeight()/2 - 5" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_RIGHT" font="Graphics.FONT_NUMBER_MEDIUM" />
        <label id="message" x="center" y="dc.getHeight()/2" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_MEDIUM" />
    </layout>
    
    <!-- A generic, centered layout for Edge devices. -->
    <layout id="EdgeLayout">
        <drawable class="Background" />
        <bitmap id="img" x="dc.getWidth()/2 + 20" y="dc.getHeight()/2-3" filename="../drawables/None.png" />
        <label id="label" x="center" y="3" color="Graphics.COLOR_LT_GRAY" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
        <label id="value" x="dc.getWidth()/2+15" y="dc.getHeight()/2 - 5" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_RIGHT" font="Graphics.FONT_NUMBER_MILD" />
        <label id="message" x="center" y="dc.getHeight()/2" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_MEDIUM" />
    </layout>
    
    <!-- centered layout for 1-field layout. Flag = 15 -->
    <layout id="FullLayout">
        <drawable class="Background" />
        <bitmap id="img" x="dc.getWidth()/2 + 35" y="center" filename="../drawables/None.png" />
        <label id="label" x="center" y="dc.getHeight()/2 - 60" color="Graphics.COLOR_LT_GRAY" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
        <label id="value" x="dc.getWidth()/2 + 30" y="center" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_RIGHT" font="Graphics.FONT_NUMBER_HOT" />
        <label id="message" x="center" y="center" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_LARGE" />
    </layout>
    
    <!-- Top Left. Flag = 3 -->
    <layout id="TopLeftLayout">
         <drawable class="Background" />
         <bitmap id="img" x="dc.getWidth()/2 + 25" y="80" filename="../drawables/None.png" />
        <label id="label" x="dc.getWidth()/2 + 10" y="45" color="Graphics.COLOR_LT_GRAY" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
        <label id="value" x="dc.getWidth()/2 + 20" y="75" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_RIGHT" font="Graphics.FONT_NUMBER_MEDIUM" />
        <label id="message" x="dc.getWidth()/2 + 10" y="75" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
    </layout>
    
    <!-- Top Right. Flag = 6 -->
    <layout id="TopRightLayout">
         <drawable class="Background" />
        <bitmap id="img" x="dc.getWidth()/2 + 15" y="80" filename="../drawables/None.png" />
        <label id="label" x="dc.getWidth()/2 - 10" y="45" color="Graphics.COLOR_LT_GRAY" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
        <label id="value" x="dc.getWidth()/2 + 10" y="75" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_RIGHT" font="Graphics.FONT_NUMBER_MEDIUM" />
        <label id="message" x="dc.getWidth()/2 - 10" y="75" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" /> 
    </layout>
    
    <!-- Bottom Left. Flag = 9 -->
    <layout id="BottomLeftLayout">
         <drawable class="Background" />
        <bitmap id="img" x="dc.getWidth()/2 + 30" y="35" filename="../drawables/None.png" />
        <label id="label" x="center" y="0" color="Graphics.COLOR_LT_GRAY" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
        <label id="value" x="dc.getWidth()/2 + 25" y="30" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_RIGHT" font="Graphics.FONT_NUMBER_MEDIUM" />
        <label id="message" x="center" y="30" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
        
    </layout>
    
    <!-- Bottom Right. Flag = 12 -->
    <layout id="BottomRightLayout">
         <drawable class="Background" />
        <bitmap id="img" x="dc.getWidth()/2 + 15" y="35" filename="../drawables/None.png" />
        <label id="label" x="center" y="0" color="Graphics.COLOR_LT_GRAY" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
        <label id="value" x="dc.getWidth()/2 + 10" y="30" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_RIGHT" font="Graphics.FONT_NUMBER_MEDIUM" />
        <label id="message" x="center" y="30" color="Graphics.COLOR_WHITE" justification="Graphics.TEXT_JUSTIFY_CENTER" font="Graphics.FONT_TINY" />
    </layout>
    
</layouts>

And here is where I set the layout in the onLayout() function:

    // Top left quadrant so we'll use the top left layout (3)
       	if (obscurityFlags == (OBSCURE_TOP | OBSCURE_LEFT)) { 
            View.setLayout(Rez.Layouts.TopLeftLayout(dc));
            
        // Top right quadrant so we'll use the top right layout (6)
        } else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT)) { 
            View.setLayout(Rez.Layouts.TopRightLayout(dc));
           
        // Bottom left quadrant so we'll use the bottom left layout (9)
        } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_LEFT)) {
            View.setLayout(Rez.Layouts.BottomLeftLayout(dc));
          
        // Bottom right quadrant so we'll use the bottom right layout (12)
        } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_RIGHT)) { 
            View.setLayout(Rez.Layouts.BottomRightLayout(dc));          
            
        // square device (edge) layout (0)
        } else if (obscurityFlags == 0) { 
        	View.setLayout(Rez.Layouts.EdgeLayout(dc));
        	
        // one-field full layout (15)
        } else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT | OBSCURE_BOTTOM | OBSCURE_LEFT)) { 
        	View.setLayout(Rez.Layouts.FullLayout(dc));

        // For all other fields, use the generic centered layout
        } else {
            View.setLayout(Rez.Layouts.MainLayout(dc));
          
        }

  • What device?  Remember, some only have 16k for DFs.

    What do you see on the bottom line in the sim for memory when it works?  How about view memory (look at peak memory there)

  • in the bottom of the sim it says 25,3kB/28,6kB. I have tried Fenix 5 and various forerunner models 

  • What does it say for peak under view memory?

  • I guess my DF is getting a bit to heavy then. 

  • in my latest test i got this:

    Error: Out Of Memory Error
    Details: Failed invoking <symbol>
    Stack:
    - MainLayout() at Rez:41 0x10001d6a
    - onLayout() at C:\Users\fredrik\git\glucose-tracker-df\source\glucosetrackerdfView.mc:80 0x100012d7

    row 80 is where i call setLayout:

    View.setLayout(Rez.Layouts.MainLayout(dc));

  • You can use a few prinln calls with

    Sys.getSystemStats().usedMemory

    to see where you are memory wise in various places in your code.

  • Ok. I will try that. Is it possible to see where most memory is consumed from the memory view in the simulator? 

    so I guess this issue is not related to having to many layouts then? It just happened to run out of memory when I make the set layout calls (?)

    each layout includes a bitmap which I guess consumes some memory. Regardless of how few layouts I have in my layouts xml file, I run out of memory if I use multi field layouts in the simulator, meaning It loads multiple layouts or the same layout multiple times. This is not a real life scenario as I can only load my df once per screen in a real target but a pain not to be able to simulate the UX for all different fields in the simulator so need to get it fixed somehow. Not sure though how much memory I need to free up though and how to go about it but I’ll look around for solutions  

  • My guess is that you're running out of memory because you have the current layout in memory and onLayout is getting called. You dutifully load the requested layout, and the system runs out of memory when you do.

    If this is the problem, the workaround is pretty simple. Unload the current layout before loading the next layout. Here is a paste of what you should need to do given the code you've provided above.

    // Clear the current layout
    View.setLayout(null);
            
    // Top left quadrant so we'll use the top left layout (3)
    if (obscurityFlags == (OBSCURE_TOP | OBSCURE_LEFT)) { 
        View.setLayout(Rez.Layouts.TopLeftLayout(dc));
                
    // Top right quadrant so we'll use the top right layout (6)
    } else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT)) { 
        View.setLayout(Rez.Layouts.TopRightLayout(dc));
               
    // Bottom left quadrant so we'll use the bottom left layout (9)
    } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_LEFT)) {
        View.setLayout(Rez.Layouts.BottomLeftLayout(dc));
              
    // Bottom right quadrant so we'll use the bottom right layout (12)
    } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_RIGHT)) { 
        View.setLayout(Rez.Layouts.BottomRightLayout(dc));          
                
    // square device (edge) layout (0)
    } else if (obscurityFlags == 0) { 
        View.setLayout(Rez.Layouts.EdgeLayout(dc));
            	
    // one-field full layout (15)
    } else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT | OBSCURE_BOTTOM | OBSCURE_LEFT)) { 
        View.setLayout(Rez.Layouts.FullLayout(dc));
    
    // For all other fields, use the generic centered layout
    } else {
        View.setLayout(Rez.Layouts.MainLayout(dc));
              
    }
    

    If you wanted to look into another potential optimization, you could try to skip loading a new layout if the layout hasn't actually changed.

    hidden var mLastLayoutSymbol;
    
    function onLayout(dc) {
    
        // each call to View.setLayout and each references to Rez.Layouts 
        // generates more assembler code, which takes up code space (memory)
        // this code attempts to minimize some of that waste without making
        // the code less readable.
    
        var aLayoutSymbol;
        if (obscurityFlags == (OBSCURE_TOP | OBSCURE_LEFT)) { 
            aLayoutSymbol = :TopLeftLayout;
        } else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT)) { 
            aLayoutSymbol = :TopRightLayout;
        } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_LEFT)) {
            aLayoutSymbol = :BottomLeftLayout;
        } else if (obscurityFlags == (OBSCURE_BOTTOM | OBSCURE_RIGHT)) { 
            aLayoutSymbol = :BottomRightLayout;
        } else if (obscurityFlags == 0) { 
            aLayoutSymbol = :EdgeLayout;
        } else if (obscurityFlags == (OBSCURE_TOP | OBSCURE_RIGHT | OBSCURE_BOTTOM | OBSCURE_LEFT)) { 
            aLayoutSymbol = :FullLayout;
        } else {
            aLayoutSymbol = :MainLayout;
        }
    
        // only load a layout if the layout has changed
        if (aLayoutSymbol != mCurrentLayoutSymbol) {
            // Deallocate the current layout
            View.setLayout(null);
            
            // Allocate and initialize a new layout
            var callback = new Lang.Method(Rez.Layouts, aLayoutSymbol);
            View.setLayout(callback.invoke(dc));
            
            // Keep track of what layout symbol we loaded most recently
            mCurrentLayoutSymbol = aLayoutSymbol;
        }
    }