Memory usage with different SDK's

Hi all together, perhaps you can help
Im running in out of memory with my watchface with latest SDK 3.0.3
Many settings are implemented and the peak memory on settings changed is becoming more and more with every SDK Version.

I have check this with the same operation (change the same settings) and different SDK's with follow results:

SDK 2.4.9
Memory Usage: 79.4/92.1kB
Peak Memory: 85.5kB
Object Usage: 157/65535
Peak Objects: 290

SDK 3.0.1
Memory Usage: 79.8/92.1kB
Peak Memory: 86.0kB
Object Usage: 159/65535
Peak Objects: 292

SDK 3.0.3
Memory Usage: 79.9/92.1kB
Peak Memory: 91.1kB
Object Usage: 160/65535
Peak Objects: 366

I can't migrate to SDK 3.0.3 without reducing the functionality.
But why does the Peak memory increase so much with latest SDK.
community.garmin.com/.../1404817.png community.garmin.com/.../1404818.png community.garmin.com/.../1404819.png
  • Unfortunately, there aren't any guidelines. :(
  • As a rule, I try to stay a few k under max, including peak after a settings change. For one thing, you don't want a simple bug fix to cross the line. So there are times I'll not add a feature just to keep the "breathing room". Otherwise a miscalculation by the sim of 100 bytes, or a non-typical code path could happen and cause a crash.

    The complexity of the settings will impact their effect on memory with a change, as a single number is less than 20 numbers, a string and some booleans for example, so something to consider with settings.

    If you want to back off from the edge, look at your app and maybe take out a feature no one uses. You might also look at a few things and see there's a better way to do them after you've done CIQ for a while. There was an app I did when I started CIQ that was getting a bit large, and re-wrote parts of it a year or two back and saved about 10k with the exact same functionality.
  • Thanks, Jim.

    I'll finally have some breathing room from work, and will focus on optimization over the holidays. It's been months since I've spun up my ConnectIQ development VM.

    How do the definition of strings and settings impact memory use?
    Also, I'm used to using verbose variable names for code readability, is there an impact there?
    I guess it's time to get creative. :)

    Thanks again,
    Kev
  • The variable names themselves should have no impact.

    For setting, when app setting are done, a "new version" goes to the watch to get merged in with what's there and I think that's were the increase in peak comes from. The more or more complex the settings, the larger the peak as the new replaces the old.
  • I hope the Connect Iq team will be able to find a way to not have the send settings memory hit as this will impact all the bigger projects once they move to 3.0.....

    As a rule, I try to stay a few k under max, including peak after a settings change.

    that might be an option in watch faces, but for data fields staying a few k under max is not an option really as soon as you do something serious :)
    that having said my watch faces are also close to the memory limit, maybe some programmers will always seek to find the limits :)

    Also, I'm used to using verbose variable names for code readability, is there an impact there?

    Length of functions do have impact towards memory used but this is only a few bytes you'll save by shortening your function names... As a rule of thumb I do try to stay now below 8 chars in my projects though, even if it'll save me only a few bytes per function it's memory space I need for my apps to be able to function with all the features they have.

    It's not the first thing I'd do if I'd memory optimize a project though, maybe you have code in your project that's not used at all (yet still consumes memory space), maybe you're still using layout.xml instead of direct dc draws, maybe you haven't reviewed your code yet (each time I have taken a look at my projects and walk through them from start to finish I've been able to gain a bit of memory back)...

  • Peter, I definitely need to revisit my code. I've purged unused code, but I'm sure there are efficiencies to be gained.
  • KSodhi One thing I've found is if you load even one resource at run-time, then sadly global memory will be consumed for every resource you have, including strings (which includes app settings strings.) Luckily, this space is not dependent on the size of the resources, just the number of them. But it's still sad to see strings which you will never use in the app consume memory in any way. But if you can delete unused resources, then you could save memory at run-time.

    There are so many things that can be done to save space. I and many others mentioned these before. Some are horrible for code maintainability tho.

    There's all the standard stuff about eliminating duplicate code and streamlining logic.

    Then there's:

    - Use if statements instead of switch statements
    - Use "lookup tables" instead of if statements
    - Avoid dictionaries when possible. Use arrays when you can
    - Avoid small classes with little or no methods that could be replaced with arrays
    - "Manual inlining":
    -- Replace any number of calls to tiny one-liner functions with the function body itself
    -- Replace function that is called in one place with the function body itself
    - If you do any kind of arithmetic/initialization with literal numbers, make sure all the literals are together, so they can be optimized out. e.g. 5 + x + 10 takes more code than 5 + 10 + x.

    - If you have large global/class data such as an array or dictionary, move it to JSON resources
    --- If JSON resources aren't available for your platform, put the data inside a get() function. This is terrible for time efficiency, but saves a lot of memory from having that object exist all the time on the stack or the heap.

    Here's some horrible advice which you shouldn't take, but which might help if you are desperate to save memory:
    - Use global variables instead of class variables
    - Get rid of modules and use globals
    - Replace enums and consts with hard-coded numbers. Symbols are not free (not even when you access const/enum in your own class)
  • -- Replace function that is called in one place with the function body itself


    I have used this technique extensively to turn a long sequence of otherwise unreadable code into readable pseudo-code and in modelling I can find no evidence of a memory hit. Am I missing something?
  • RaceQs there is code/data overhead for:
    - The symbol for the function
    - The function caller: pushing the arguments on to the stack, invoking the function
    - The function callee: popping the arguments off the stack

    If the compiler could inline functions then there could be 0 overhead, but in this case there will always be overhead.

    You will not see it in terms of "x KB used" in the memory window, but if you look at the code in bytes, it will increase slightly.

    Sure, for one function it's meaningless. But it adds up over many instances. Most of the stuff I posted only adds up over lots of instances. That's why I only suggest some of it as a last resort.

    Speaking of small potatoes:

    Replace

    function utilityFn(x,y)
    {
    var a = x;
    ...
    }

    with
    function utilityFn(a,y)
    {
    ...
    }

    I thought the compiler would optimize that kind of thing out, but it doesn't. You can save tiny amounts of memory by eliminating redundant local vars. Same goes for redundant initializations.

    var x = 0; // this initialized value is never used and should be removed
    if (...)
    {
    x = 1;
    }
    else
    {
    x = 2;
    }


    But you can save a ton of memory (relatively speakingly) by, say, replacing a nicely written circular queue class with a simple array, index/size variables and inline code to read/write the queue, depending on how many places you use that queue.

    It all comes down to the tradeoff between maintainability and memory usage.
  • Thanks for that, I was monitoring memory and not app size, so didn't see any difference.


    BTW, I notice you refer to interactions with the stack, and Brian.ConnectIQ has referred to the heap in discussions about memory, which raises question about terminology.
    I know that Monkey C compiles into byte code that is interpreted by a virtual machine, so I wonder if you are using stack and heap in reference to this VM, and if so, can you point me to a description of the architecture of the VM?
    I know the Java VM stores objects in a "heap", so I assume the CIQ VM (is that the correct naming?) has a similar architecture.