Preserving memory in Monkey C


As for couple of last days I was fighting hard to preserve every single byte of memory, balancing just at the edge... maybe others will find that usefull - and even more - maybe Garmin will work on that to improve as well?

1. Do not use SWITCH / CASE construction. Instead - use IF / ELSE IF construction. It preserves memory, maybe not a lot, but always few bytes or more.

2. This is ridiculous? Do not use CONST variables. It looks like using directly values preserves memory. Don?t like it, but no choice there

3. It is beneficial to create a function whenever 2 or 3 lines of code are repeated. Just use params if required. It will save space

4. Avoid use of dictionaries!

5. For memory consuming operation try to assign to every non used variable NULL ? this will free memory

I'd appreciate - as the whole community - if others would share their findings too!
  • ...
    • Use string resources instead of strings
      ...
    • [/LIST]

    I've observed the opposite in this case: when I replaced literal strings with loaded resources my memory footprint appeared to go up, which I put down to the size of the Ui.loadResource() call and the Rez.Strings.symbol. I've made a to-do to recheck this though.

    This is an awesome thread, thank you all, as I too battle memory limits in dwMap.

    I've found Jungles to be helpful. For example instead of having to have code to request the screen width and height, I can create a jungle file for all watches of a particular screen size and then have constants in that file. Or put the screen specific code itself in the jungle file, then those constants can even be literals.



  • I was just coming here to make my first post and ask how other developers were handling this problem, and stumbled across this thread. I just wrote my first Data Field for Connect IQ, tested it fine on the fenix 5 platform and was amazed to find it wouldn't run on the Forerunner 235. Not even close - I was at 24KB with 16KB available. As an experiment I tried commenting out code until I got down below 16KB and by the time I did, I'd erased 80% of my functionality!

    I did a bit of experimenting and reached a similar conclusion to others in this thread; to lower your memory footprint, you have to abandon all principles of maintainable code. To be fair, these applets are so tiny, adopting bad programming practices wouldn't be the end of the world but I reasoned that for now I don't want to spend my time battling my way to 16K, so I'll only be supporting the newer watches. I mean 16K - really? I know we're trying to run on a shoestring power budget here, but even the Sinclair ZX Spectrum I got for my 5th birthday 33 years ago had 128K! I remember feeling hard done by when I had to work with 128MB of RAM in the first iOS SDK. Wow.
  • CIQ1 devices like the 235 have less memory for data fields (16k), while CIQ2/3 devices has much more (28k and up). Doing a complex DF in a CIQ1 device can be a challenge, but some people use some tricks to build for CIQ1 with reduced functionality while maintaining full functionality for CIQ2/3 devices. (You can use separate source, annotations to include/exclude parts, etc) Some simply don't support CIQ1 devices with a more complex DF. Sounds like for you, it's best to just think about CIQ2/3 devices.

    In reality, a great deal can be done with CIQ with the memory available, even on CIQ1 devices, but DFs there can be a challenge.
  • Urgh. I added some functionality to my DF yesterday and redesigned the UI a little using some icon bitmaps instead of text labels. Now I've broken it in all but about three of the devices I was targeting with the dreaded Out of Memory error. Looks like I'm gonna have to spend some time squeezing my DF to use less zeros and ones. I haven't exactly been careless with memory management, but I was hoping I'd get away with it. Does anyone have any tips (or tutorial links etc.) for analyzing memory usage in Eclipse? I'm from the .NET world - I've never used Eclipse before I downloaded the Garmin SDK.
  • You want to be careful with bitmaps in general and especially when it comes to the pallets used.
  • I'm quite surprised by removing CONST to claw back memory. To me, the definition of "constant" dictates that it should only be evaluated at compile time (ie, some kind of pre-compile).

    One thing I've found is that if you are using App Settings (ie, have a properties.xml file) with lots of entries, keep the ID's as short as possible (1 to 2 chars) as long ID names (every character) seems to take up memory!
  • My turn to contribute something to this discussion:

    1. Experiment with string resources vs inline strings. In my experience, a string resource uses more memory than an inline string if the string is used only once.

    2. Shorten your setting names. I saved a few hundred bytes by shortening all my user settings from long descriptive names to one or two character abbreviations.

    3. All string resources cost memory, even if they are only used in the app settings. Don't declare string resources you don't really need.

    4. The ternary operator seems slightly more efficient for me than if/else statements. This one might be BS, but it certainly didn't hurt. It's useful for setting a single variable to different values based on multiple conditions. For example:

    var topGridLineY =
    round240 ? 80 :
    round218 ? 73 :
    semiRound215 ? 60 :
    0;


    5. This one has been covered above to some extent but I hadn't fully grasped it so wanted to make this explicitly clear: your code itself takes up memory. I had thought that talk of reducing the code complexity meant that you would gain memory advantages as a side effect (i.e. getting rid of a class gets rid of the memory used to store the class instance reference). But unless I'm mistaken, it's more than that. The memory limit you are working within is not only for the memory allocated by your program, but for the program code itself.

    For this reason you should never have any lines of code that aren't necessary for the program to function. For example, I needed a max() function, so I wrote a min() function as well, even though I didn't have a use for it yet. That was wasting memory. That's why you should drop System.println() functions for release for example.

    6. Don't read drawables from resources until you need them. I was pre-loading all my icons into BufferedBitmaps so I could use them when needed, despite the fact that user settings could mean I never needed them anyway. Only pull them in when you know you will need them.

    7. Bitmaps aren't too bad if you use a palette. I've included about eight 20x20px icons in my project, all provided as plain black on transparent PNGs and I colour them with a palette. They're not all loaded at the same time, and use around 180 bytes each.

    My data field is currently 20.8K and considerably more complicated now than it was a couple of weeks ago when I was at nearly 30K. It's been interesting working within these miniscule limits and I'm still rather in awe of people who have managed to stay inside the 16K limit for CIQ1 data fields, but at least I've got plenty of wiggle room now to add features to my data field and still support a good range of devices.
  • For #6,7, another trick for icons is to not use bitmaps for icons. Use a custom font. It's easy to change color without reloading, in the same way you change color for any font

    dc.setColor(Colors.icons,Gfx.COLOR_TRANSPARENT);
    dc.drawText(x,y,iconFont,"AP", Gfx.TEXT_JUSTIFY_RIGHT); //Alarm and phone icons in my font


    Draws two icons, using the color for icons based on app settings. No bitmaps or palettes involved, and only a single draw in this case. While I've not done any tests, my gut feel is this will result in lower memory usage, as long as the iconfont font uses a reduced character set.(which can also be filtered based on the app)
  • I’ll add my 5 cents if it’s still relevant to someone. This has already been mentioned here, but not so explicitly. At least, I did not immediately notice this. Perhaps because I'm not quite a programmer, I had fun at my leisure. I mean: Do not use CONST variables !!!
    Replace the type lines in the code: TEXT_JUSTIFY_CENTER, FONT_NUMBER_MILD, COLOR_DK_RED and so on with their direct numerical values ​​and you will save some more memory.

    For example:

    dc.setColor (Gfx.COLOR_DK_RED, Gfx.COLOR_TRANSPARENT);

    on
    dc.setColor (0xFF0000, -1);

  • I do the same as you. It saves crucial bytes, but comes with harder to maintain caveat.