Large chunk of ram for buffer: should I declare it as static/global or allocate dynamically?

Hi,

I will need to use a large chunk of RAM (9KB) as temporal buffer, to download something from server, do some processing, then the purpose of that buffer will be done. In such case, should I declare it as global array or local array inside the function that uses it?

For small arrays, the answer seems obvious, local. But for array this large, I am not quite sure. The argument against local array is dynamically allocating 9KB of ram may take long or crash system. The argument against global array is, we essentially have a large chunk of RAM that will be seldomly used.

Please advise, thanks.

local doesn’t mean dynamic. Local is usually on the stack, especially a std::array whose size you need to know at compile time.

having it as local variable mean that you cannot use it outside your function. It will go out of scope and be cleaned up when the function returns.

The question is: is your stack big enough to hold the array? 9kBytes is a lot and the maximum size is implementation defined.

You can make your array global, if it’s initialized, it will live in the data section. Your binary size will increase but you know you’ll have the space to do what you need.

If your array is only used in a specific class or struct, you can also declare it as member variable, and then declare your objects globally (this is was we do, we statically initialized all the “big” arrays we need to make sure that the memory is counted and we don’t run into stack overflow)

If the array is not initialized, it might end up in the bss, without any additional space, but then I’m not sure what will happen when you use it.

You can also dynamically allocate the memory using a unique_ptr or shared_ptr then access the memory. This is nice, but you need to make sure you have enough heap.

If the array is actually a vector, you can use custom allocators and placement new by statically creating a buffer and then using this buffer as a memory pool for your std::vector.

Plenty of options!

IMHO and experience, having things statically defined and present in your binary avoids a lot of bugs.

My concern is, if I declare this large array as global, then it will stay in stack forever. As a result, heap will have less room. Because I have other stuff like mailbox etc. that lives in heap and depending on dynamically allocated ram to work, I feel guilty for reserving this large of space for an array that is only used once or seldomly used.

The operation that uses this large array as buffer is not critical timing wise, I can wait until heap has enough room to allocate. Is there any other factor that I need to plan ahead?

I don’t have an answer to that, you need to measure in your specific case. arm-none-eabi-size can give you some hints, mbed also has a runtime statistics option that you can enable to measure this kind of things.

What MCU are you using? How much RAM/ROM do you have?

This usually “never” happens, so you might be waiting for quite some time… The main reason being memory fragmentation.

Even if you new/delete and don’t leak memory, you end up with holes in your heap. As time passes by, it will get more and more difficult to find one continuous chunk of 9KB available, so you’ll get an allocation failure even if the total heap available is bigger than your buffer.

This will get worse if during the lifetime of your application, you need to allocate this chunk multiple times.

Your app will crash, you’ll reboot and start again.

Reason why you get holes is because C++ doesn’t have garbage collection. If you try to be smart and merge the chunks, you’ll invalidate all the pointers pointing to those chunk.

Java garbage collection works because you don’t have direct access to memory pointers.

The application is designed to run for months if not years without rebooting. Memory fragmentation is what I missed. We will go with global array.

STM32F429 as of now, we can move up to F7xx if needed. So we can afford to have 9KB sitting around even if it is not used frequently.

1 Like

A little precision here: global doesn’t mean stack, it will be in data section, my understanding is that you’ll access it directly, no need for RAM in that case. So your stack and heap available will be the same w/ or w/o the global array.

See flash - PROGMEM on Arduino Due (ARM Cortex M3) - Arduino Stack Exchange

If you put it in a header, don’t forget to use inline in front, especially if you include it in different TUs

1 Like