Best practices for reducing memory usage?

Former Member
Former Member

Hi all,

I am currently sitting at 86kb / 91.8kb for my first Garmin watchface, and I'm looking to reduce memory usage. 

So far, I've found the following has helped quite a bit:

  • Reducing the amount of bitmaps being used, when possible (by using fonts or drawing shapes instead)
  • Reducing or removing unused code, such as calls to System.println() and others
  • Only loading fonts necessary to the appropriate screen resolution 

What other memory reduction tips do you have?

Thank you!

  • yes, yes you are right but in many situation operation on global var is simple simplest Slight smile

    but please answer, Is my my thinking correct 2x768 or 3x768? becouse it's work to me to rewrite code and I don't want to waste time if there influence on memory.

  • Maybe I'm missing something here, but a background process and its associated app have different pools of memory and different memory limits.

    e.g. On a Fenix 6 the memory limit for a background process is 32768 and the memory limit for a watchApp is 131072.

    So you don't need to worry about the total amount of memory consumed by some large object across all processes, but the just the peak amount for each process.

    IOW, does each process (regular app and background service) have enough room for your 5 KB object?

    Then again, as Jim pointed out, why do you need this big object as a global variable? It sounds like it doesn't have to be in the background process, so if you simply rewrite your code so the background process would never load the bitmap / other big object, then you don't have to worry about its memory impact on the background services, which does have a much lower memory limit.

    Also, I'm pretty sure there's only 2 processes here. Not sure where this concept of a 3rd process for the view is coming from.

    Think of it this way.

    • App Process = all of the code
    • Background Process = all of the code annotated with :background (and the main App class) (except for AppBase.getInitialView())

    They don't share memory but they do share code.

    So all the code for your background process will be a subset of the main app. What you load into the background class depends on you. If you choose to load a very large object into both processes, you only have to worry about the memory impact on each individual process, not the total impact on both processes together.

    If you must leave that object as a global variable, you can choose not to initialize it in the background service, which means that it would only take up 4 bytes (or whatever). getInitialView() isn't called by the background service, which means that anything that happens in your view (or in that function itself) won't happen in the background service.

  • Please, don't ask me why I need global. I am an experienced developer and know how/when only there is a lot of  types of devices, problem with sdk, limitation (memory, time req...)  so I heave to use trick instead on focus of development...

    Why you don't simple answer on my question. Ok my real situation

    Don't  ask why there is ab. 17k, there is...

    And question. Is this 17k is twice ones get my memory from 92kB and second eats 50% of background process memory?

  • I tried to answer your question. My understanding is that the app and background service have separate pools of memory, so you don't have to worry about *total* memory impact, but only *individual* memory impact for each process. The simple answer is that you're asking the wrong question as far as I can tell.

    So the question isn't whether your object takes 2 x 17 KB of memory.

    The question is:

    - Does my app have enough memory to spare 17 KB?

    and

    - Does my background service have enough memory to spare 17 KB?

    And I said that there's 2 processes, not 3 processes, as far as I understand. I also said that if you don't need the object in your background process, you can simply choose not to initialize that variable in the background process. i.e. Initialize the global variable in getInitialView() or the view itself.

    Anyone who's reading this: If I've said anything incorrect here, please correct me. Thanks!

    And I don't really care whether you use a global, I use globals in monkey c sometimes. It's right there in my list of ways to save memory.

    What I really don't understand is why you need to initialize that variable in your background process if it doesn't need it or if you're worried about the memory impact (as the background process only has 32 KB of available memory). Just because you have a global variable doesn't mean it has to be initialized in both processes.

    Why you don't simple answer on my question.

    I tried. I'm sorry my answer wasn't helpful. I'm not a Garmin employee and it isn't my job to post in this forum. I'm not an expert about everything CIQ either, to be clear.

    ¯\_(ツ)_/¯

    As far as your screenshot goes, I can't tell from looking at it why your code is 36722 or your Entry Point has 38600 bytes of children. I will say that sometimes the size of children is double-counted, IIRC (in that case, if you expand the details, you would see duplicate object IDs, IIRC.)

    Sometimes the best thing you can do to determine memory impact is to experiment with your code. Write the code a different way and compare the memory usage, especially the peak and current usage.

  • still no answer Slight smile maybe bad question, sa repaet:

    According to: https://developer.garmin.com/connect-iq/connect-iq-faq/how-do-i-create-a-connect-iq-background-service/

    You also can’t pass information between the main process and the background with global variables. The word “process” is important here: global variables are per process, so the same global is only global for that process. A variable defined globally exists in both the main process and background process, but each maintains its own copy and they’re never synced..

    I does IT mean that my global var are in two copies? I think that they are but maybe not consumes memory everything depend on order. If I first "load" into global var data in VIEW for example:

    var gDeviceSetting=null;// global

    function setGlobal()

    {

      gDeviceSetting= SYS.getDeviceSettings();

    }

    an than is create background in background will be only null variable.

    I was a question. Just in case I rewrite code.

    My app has 17KB as it run but on same device I have a problem and maybe there is problem with background memory so my question.

    why 36722? There is 8 buffered bitmaps :)  the size depend on size and shape of  screen

    in this example consumes "only" 20657 :)

  • I don't how else to say this, but my understanding is:

    - The app is in its own process, has its own memory, and has its own memory limit

    - The background service is in its own process, has its own memory, and has its own memory limit

    Think of the background service as a separate app that just happens to share some of the same code as the main app.

    I don't know what you mean by "first load global variable then create background process". That's not how it works, as far as I know. You don't get to control when the background process is created and there's no common execution history. It's not like forking a process or spawning a thread. It's two different processes which share some code.

    My understanding:

    - The app has *all* of the code, and the app process calls getInitialView() but not getServiceDelegate()

    - The background process has the app class and all code annotated with :background. It calls getServiceDelegate() but not getInitialView().

    Therefore, if you want the big object to be loaded in the main app and not the background process, then you load it in getInitialView(), the view itself or something that isn't annotated with :background. If you have a big resource you only want to load in the background, load it in getServiceDelegate() or the service delegate itself.

    Either way, the background process and the main app have *separate* memory pools. It's up to you to determine what code you include and data you load in each of them to make sure you stay under the memory limit for each process.

    Again, if I've said anything incorrect here, I welcome corrections. Thanks!

  • Please answer a question Slight smile What does exactly mean this sentence fro documentation:

    A variable defined globally exists in both the main process and background process, but each maintains its own copy and they’re never synced.

    let' see this code

    //first file
    var globalVar1=null;//for example big bitmap 5kB
    const cXXX = 12;
    
    class PSX1_View extends UII.WatchFace
    {
        ...
        function initialise()
            globalVar1 =1;
        function x()
        {
            print(cXXX);//<---------- prints 12
            print(globalVar1);//<----------1
        }
    }
    
    
    //second file
    (:background)
    class PSX1_App extends APP.AppBase
    {
        function getInitialView()
        {
            mV = new PSX1_View();
            print(cXXX);//<---------- prints 12
            print(globalVar1);//<----------1
    
            return [mV];
        }
    
        function getServiceDelegate()
        {
            print(cXXX);//<---------- prints 12
            return [new BackgroundService()];
        }
        ...
    }
    
    //third file
    (:background)
    class BackgroundService extends SYS.ServiceDelegate
    {   
        function x()
        {
            print(cXXX);//<---------- prints 12
            print(globalVar1);//<----------null!!!!
    
        }
        ...
    }

    ok, let's finish I think, that backround and app has the copy of global var but only const or initialised exist in both it;s probably run this way

    global

    global

    code

    ----

    start app - creating app get it's code and globals

    start back - get code and globals but becousu there is no code  in annotated (:background) that using globals then consumes only memeory for themselves

  • Please answer a question

    I really don't know how to answer your questions except to explain my understanding of how background processes work.

    What does exactly mean this sentence fro documentation:

    A variable defined globally exists in both the main process and background process, but each maintains its own copy and they’re never synced.

    It means exactly what it says. I don't know what's unclear about it.

    - The main process has all the global variables, in its own memory which is not shared with the background process

    - The background process has all the global variables, in its own memory which is not shared with the main process

    Like I said, just imagine them as two different apps which happen to have some code in common.

    ok, let's finish I think, that backround and app has the copy of global var but only const or initialised exist in both it;s probably run this way

    global

    global

    code

    ----

    start app - creating app get it's code and globals

    start back - get code and globals but becousu there is no code  in annotated (:background) that using globals then consumes only memeory for themselves

    Yeah, your description and the code you wrote is what I've been trying to say over and over again.

    - If you set a global variable in main process only (i.e. getInitialView()), then the background process won't see that value. Therefore, if you want to load a big resource only in the main process, then load it in code that only runs in the main process

    - If you set a global variable in the background process only (i.e. getServiceDelegate()), the main process won't see that value

    They're separate processes, they don't share memory, they share code.

    Sounds like you've worked it out, so hopefully it's all clear now.

  • Np. Legit wish I could've been more helpful.