Out Of Memory Error on dictionary declaration

While working on my very first Garmin project I'm getting this error Error: Out Of Memory Error
Details: Failed invoking <symbol>

I think this happens because I'm trying to declare a dictionary from an extreamly long string. It has more than 5500 characters. I generated this string from a json file using python because I want to make my data field run on a forerunner 235 and I found out that this device can load resources because of the limited api level. So I decided to just generate an .mc file with the array in it. All looks good though.

Why can't I create a dictionary like this? Is there an other way to get this data into my app? 

  • Thanks for the extensive explanation. I think I get it now. I'm going to look at it tomorrow when I fresh again. 

    I just did some test to see when things pop out of memory and it was around a surprising 30 locations when using a dict. I've also tried splitting them up into multiple dicts but that didn't change a thing. I'm a bit worried that it's going to be really hard to get 114 location into my app even with the suggestions above. If I would use a later api I could use a json file as a resource file. Would that solve something?

  • If I would use a later api I could use a json file as a resource file. Would that solve something?

    If the data is still in the form of dictionary where each element is an array, it'll still consume lots of memory. Using a JSON resource would just make it easier to load your flattened array into the app (since you wouldn't have to encode it as a string, store it as a property,  and parse the string after loading it.) But then you couldn't deploy your app to older devices.

    So even if you use a JSON resource, you still want to optimize the representation of the data for when it gets loaded into your app.

    Did you try just having declaring the flattened array as code in your app?

    e.g.

    function getLocations() {

      return [

        "Location1",

        ...

       ];

    }

    If the data needs to be accessible all the time, you don't have to wrap it in a function. If the data is only required some of the time, it could be helpful to wrap it in a function, because then the data won't consume memory when it isn't needed (and you can use that extra memory for other stuff). The drawback of this approach is that the code for constructing the data will use up memory at all times. But perhaps the memory you saved from using a flat array will be enough.

  • If you are hard coding this stuff, either by way of resources or properties, why not just do it in the code in an easy to access and memory cheap manner like this?

    var locs=["Loaction1","Location2",...];
    var lats=[51.4338707, 51.4323701175,...];
    var lons=[4.9975666534,5.03289832,...];

    The lat/lons will already be floats.  Using a scheme like this I store over 1000 lat/lon pairs in one of my apps

  • I tried putting the <properties> lines in the manifest.xml file but I'm not sure if that is the right spot to put them because I'm getting an error. So where do I need to put those? Sorry I'm a real noob

  • It would need to be in a separate file (like properties.xml) under the resources/ folder.

    But like Jim suggested, you could just try hardcoding the data in your app first. Then, if you find that you need to save more memory in the future, you could move the data into a string property or JSON resource.

  • If you are able to store a 1000 of these values like you show above I don't understand why I get an out of memory error when I try to declare just 40 items in a dict? 

  • There's overhead associated with a dictionary and with each array (8 bytes per array, IIRC).

    Also, the 235 is pretty old -- newer devices have at least twice the memory for data fields.

    If you really want to dig into it, you'd have to run your app in the simulator and use the memory viewer before and after making changes to your data structures. Then you could see the impact of adding one entry to a dictionary (for example), to both the object size and the code size (both of which take up memory).

  • Yes, I use it to draw a breadcrumb trail, saving the lat/lon every minute.  Dictionaries can waste a bunch of space.  Here's the app: https://apps.garmin.com/en-US/apps/116a5b59-29ae-4397-a70e-907d7e5f8e44

    it's about 100k on devices without onboard maps and has 12 data screens.

    Here's the breadcrumb trail as a data field, and runs on a fr235, but the array is only 200 pairs long.

    https://apps.garmin.com/en-US/apps/d741d7b4-8b26-401c-a5bd-0ac91891575d

  • That's a great idea. I'm going do that just because it's interesting.

  • Something in my app is eating to much memory I guess. I currently have 114 locations that I need in my data screen. I've split everything up so I have 3 arrays now. Name, Lat and Lon. As soon as I enable the Lat and Lon array I run out of memory again. That is without the Name array. I saw that the 235 has only 16kb of memory per data screen which is half of what most devices have. 
    I think in the end I might have to go with the "properties" approach however that I'm not sure if that will save anything since I have to load them in anyway? There was a short moment where I had the Lat and Lon array loaded in but as soon as I added some code it runned out of memory again. 

    Would generating an array from a long comma separated string in the end save memory? I don't really get how that saved anything since you have to load it in eventually?