Array Memory Consumption

This was unexpected. Now that I'm using dynamic arrays... using the "add" function to extend an array on-demand, I wanted to watch freeMemory to avoid issues.

So I tested the increment memory footprint of adding an integer -vs- a float. Both incremented the used memory by 8 bytes.

Did you think that would be the case?

  • Well this has come up over and over again in the forums (and I know you have been here for many years), but here goes again.

    Each array element of a "small 'primitive'" (*) takes up 5 bytes of memory:

    - 4 bytes for the value (32 bits)

    - 1 byte for the type (i.e. the field that specifies whether the value is a Number, Float, Null, etc.)

    --

    (*) i.e. the built-in 32-bit types which fit on the stack:  Number, Float, Boolean, Null

    (**) inb4 Garmin says there's no primitives in monkey c because everything is an object. yes, but they also use(d) the word "primitive" to describe these types, and these types have far less overhead than the "non-primitive" objects, which have 80 bytes of overhead even for an empty class.

    - the other "primitives" are Long, Double and String. These are all allocated on the heap, but they still lack the huge 80 bytes of overhead used by other classes

    - the built-in containers Array and Dictionary probably can't be described as "primitives" but they still have much less than 80 bytes of overhead. Array has 15 bytes of overhead and Dictionary has something like 30-ish bytes iirc

  • The difference of 8 bytes that you're seeing can be accounted for by the fact that the total memory used - as reported by the System.getSystemStats api call  - is always a multiple of 8 bytes. 

    If you were to do a more scientific test, like looking at the impact of adding other, larger amounts of Numbers and Floats, you'd probably see the impact is always at most 5 x number of added elements, rounded up to the nearest 8.

    e.g. Without even checking, I would say that with the code you are using to measure the difference (System.getSystemStats()):

    - Adding 1 Number to an Array would result in up to an 8 byte difference (5 rounded to nearest 8), as you said

    - Adding 10 Numbers would result in up to a 56 byte difference (50 rounded to nearest 8)

    - Adding 100 Numbers would result in up to a 504 byte difference (500 rounded to nearest 8)

    Or, you could just look at the object size in the sim's memory viewer, since this number is not rounded. It would become very clear that:

    - An empty array uses 15 bytes (and this is the overhead for all arrays)

    - An array of 32-bit primitives uses 15 + 5 * number of elements

    If you use Long or Double instead (64-bit types), it's 13 bytes per element:

    - 1 byte for type

    - 4 bytes for pointer to value

    - 8 bytes for value

    Btw, this is why a ByteArray is more efficient than a regular array of Numbers.

    In a ByteArray, 1 byte of data takes exactly 1 byte of array space.

    In a regular Array, 4 bytes of data takes 5 bytes of array space. That is a 25% penalty.

    e.g. If you store 100 bytes in a ByteArray, this will use 100 bytes (plus whatever the fixed overhead is for ByteArray)

    If you store 100 bytes (as 25 Numbers) in a regular Array, this will use 125 bytes (plus the Array overhead of 15 bytes)

    using the "add" function to extend an array on-demand,

    You're really obsessed with the add function even though it's been explained that this is actually *worse* for memory and performance than the alternative of allocating a fixed-size array. In general I wouldn't use it for large amounts of data that could run up against my app memory limit, because I'd probably be effectively halving the max amount of data I could store in memory.

  • For some uses I do prefer the add function - when I collect elements every X seconds over the duration of an activity that could last 30 mins or 24+ hours. I guess I could pre-allocate a huge array every time guessing at the ultimate need. Or just perform an add every 30 or 60 seconds or whatever my frequency is.

  • great analysis of the memory usage. thx!

  • when I collect elements every X seconds over the duration of an activity that could last 30 mins or 24+ hours

    Out of curiosity:
    If X is every 5 seconds, for example, do you need this interval for the entire activity? Or could/should this interval grow with the duration of the activity?