Question

I usually have no problem deciding whether some data has to be global, static or on the stack (No dynamic allocation here, so no use of the heap). I have also read a few Q/A such as this one but my question is more specific since it involves a huge amount of data, huge compared to the system memory.

I'm working an existing code that I try to improve (design, possible issues, performances, etc.). This code runs on an old 8bit MCU with only 4KB of RAM. In this code I face the use of an array of almost 1KB (yes, 1KB on a 4KB RAM system). Each byte of this array is used, that's not the question. The problem is that this array is a static array in the file where it's declared, so its life cycle is the same as the program one (i.e. can be considered infinite).

However, after reading the code, I just found out that this array has no need of an infinite life cycle, it's built and dealt with in a fully procedural way, so we should be able to declare it only in the function where it's used, this way it would be on the stack, and we would therefore save this 1KB of RAM.

Now the question : Would this be a good idea? From a design point of view, if it doesn't need an infinite/global lifecycle, it belongs to the stack. But hey, that's 1KB out of 4KB, isn't there any drawback of allocating 25% of the RAM like this? (that might be 50% or more of the stack)

Could someone share some experience with this kind of situation, or do someone think about any valid reason not to put this array on the stack? I'm looking for technical drawbacks as well as comments on the design.

The only thing I'm conscious is that I have to make sure I actually have 1KB of stack free when entering this function. Maybe that's all what I have to take care off, maybe not.

Was it helpful?

Solution

The only thing I'm conscious is that I have to make sure I actually have 1KB of stack free when entering this function.

Yes, and that is a strong constraint. You'll better be sure statically than you do have such a large space available on the stack. If the code is small, if you are using a recent GCC to compile your code, see this.

BTW, some cheap microprocessors might make use of a "large" call frame more costly than a "normal" one (e.g. because their instruction set would favor a one-byte offset from the stack pointer). YMMV.

Also, if you are coding in C and if you feel that your large array can have its space reused for other purposes you might consider making it a union member (with a global variable of union type). Yes, that is quite ugly.

Alternatively, you could consider coding some primitive heap allocator suited to your application (and it could have an API different of malloc & free ....).

OTHER TIPS

People tend to be cautious with a large stack, because it grows backwards in RAM and overwrites values of variables, leading to unexplainable behavior. It gets even worse, because you need to know the lowest possible stack pointer address and subtract the size to allocate when entering the routine.

This is all a job for the hardware memory management (should generate traps or faults when a stack overflow occurs) or for the compiler, given it has features for this kind of analysis.

Otherwise, you can do what you want with your RAM.

As previous answers have pointed out, I would also first recommend leaving the array static if it fits to memory. In most cases, it is much more important to have deterministic memory footprint, even if it means that you "waste" memory for variables not used all the time. Putting large arrays to your stack will far too easily blow it out, and stack overflows tend to cause hard-to-find and hard-to-reproduce problems (if you can't use MMU to protect the stack).

The suggestion to share the block with some other data with union is IMO valid, although it can also be source for hard-to-find problems, if you locate wrong variables in to it.

If you are running out of memory and desperately need to make shorter-living variables to share it, before moving the array to stack, I would consider adding dynamic memory allocation, even though it has its own drawbacks. In this case it might not be an answer, as the array sounds pretty large compared to available memory.

You have one other option if you have some kind of flash storage. You can trade off speed of access for ram by storing your data in flash and reading & searching there. You would only need to load one record at a time into ram. It will be slightly more complicated if you need to be able to update the records. You will need a segmented wear-leveled mechanism. I have done this in the past and included an index to speed up access.

Especially when working with embedded systems, you want as much of the possible failures to happen at compile time and nothing ever fail at run time (nice if we could achieve this, though...).

Making large arrays you might need in arbitrary states of your program statically allocated does exactly that - The linker will eventually warn you "this doesn't fit into RAM", whereas stack allocation would simply make your program crash with hard-to-debug stack overflows.

Licensed under: CC-BY-SA with attribution
scroll top