Acknowledged

ByteArray addAll() not Memory Efficient

When using the addAll() method of Lang.ByteArray, peak memory usage implies that the ConnectIQ framework is doubling the size of the array being appended to instead of extending it by the size of the appended array.

For example, let's say we create a 1K byteArray called myArray and run the following code starting with an empty byte array, longByteArray:

while(longByteArray.size() < 32768) {
    longByteArray.addAll(myArray);
}

An efficient implementation would grow peak memory usage by ~1K more than longByteArray.size(). Instead, we see peak memory usage growing with longByteArray.size() * 2 + 1024.

It may also be worth noting that the Monkey C extension for Visual Studio code will time out as the array grows if a developer sets a breakpoint on the addAll function above while the watch window is open to longByteArray.

  • To avoid issues with contiguous memory, I'd be ok with preallocating the space and then using addAll(), but addAll() still doubles the memory unnecessarily.

  • It needs the original array when doing the add() so it can be copied over to the new (larger) space.  The memory after the original arry is likely used for something else, so the original array can't just "grow".  This and the watchdog are things you need to consider in your design.  Doing an add() or addAll work fine for smaller arrays, but you'll still see the memory double for a time, but won't be as much of an impact.  When you use larger arrays, can be a huge impact.

  • Thanks for the reply. Ideally this wouldn't be expected - CIQ should not have to double the size of the original array when calling add() or addAll() since it should be able to calculate how much memory will be needed at the end of the operation and allocate accordingly.

    We can certainly try to work around the memory problem with add() or addAll() by preallocating the array as you suggest, then running a loop like:

    for(var j = 0; j < 32; j++) {
        for(var i = 0; i < 1024; i++) {
            longByteArray[(j << 10) + i] = myArray[i];
        }
    }

    However, the watchdog timer will time out before this loop completes, so using a native function like addAll() would be better if it were as memory efficient as the method you suggest. Since addAll() is not memory efficient, I still think there is an opportunity for improvement in the CIQ framework.

  • This is expected and is the same for an Array.  When an Array (or ByteArray) is created, CIQ uses enough memory for the initial size.  When you do an add() (or addAll() ). CIQ only had memory allocated for the current array, so it needs to then allocate memory for the new (larger) array, and the copy over the original array to the new array, and than has memory to do the add().. 

    To avoid this "double memory", create the original array as large as you'll ever need and keep track of where the free space in the array starts. In your case, something like 

    var ba=new [32768]b;