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.

  • , I'm sure the collective intelligence in this forum can come up with creative workarounds, but I'm hoping an improvement could be made in native CIQ code since anything we'd do in the VM would be less efficient. A class or a loop like the one below "works" but isn't as scalable or as time efficient. The VS Code extension issue inspecting large arrays is also a problem regardless.

    I'm trying to keep this thread closer to theory than specific application, but to answer your question, in the case where I discovered it, I was working with static data. Back then, I'd tried plenty of tricks to coax addAll() to act how I wanted, like pre-allocating the array as  had suggested more recently, but native functions like addAll() don't seem to compare to the loop below in terms of peak memory efficiency. It may go without saying that I ended up not using addAll(), but the API might be stronger if it were improved.

  • Unfortunately, there is many places (e.g. dictionary, settings) where ciq runs that way and don't expect it will be fixed soon or ever.

    Maybe solution is writing your own class that emulates system's array.

    BTW, does this big array have dynamic or static data?

  • I'm not sure I follow. If I preallocate an 8K array and rubber stamp a 1K array 8 times, the peak memory usage looks fine:

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

    The exact sizes here (8K vs. 32K) don't really matter - the point is that CIQ could provide a native function for assigning blocks to a preallocated array without using more memory than is necessary. The above loop proves that it is possible to do this in VM code (running this in the simulator I see peak memory usage about 1K above total memory usage), so it should be possible for CIQ to the same in native code.

  • If you are doing an add() or addAll() the original array only has enough memory allocated for the original array.  That's why it needs to allocate memory for the new (larger) array.

    By the way, what will you being with this 32k ByteArray?  You can't save it to storage or send it using comm...

  • Let's assume the original longArray were preallocated using:

    var longArray =new [32768]b;

    Why could there not be a native CIQ function that takes a 1K myArray and adds it to longArray 32 times without using more than 33K? Basically, it could do in native code what this loop does if the watchdog didn't time out:

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

    The above loop is memory efficient but not time efficient, but CIQ native code could improve this.