11

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.

  • 4
    You wrote, "and therefore save this 1KB of RAM". Save it for what? That 1KB has to be available when you need it for the array so why not make a static allocation? Do you have another use for the memory when it's not needed for the array? – kkrambo Oct 11 '16 at 14:46
  • @kkrambo At some point we consider a system is full when we can't add anything more on the RAM, whether it's something static or on the stack. If we put this array on the stack only when we use it, it'd let place for another functionality as long as they are not used at the same time. But the question is totally legit, at the moment if we don't change anything in the SW, we don't need more RAM ;) – Tim Oct 11 '16 at 14:52
  • 1
    Could you clarify whether this array has content that always remains the same or if it changes when the function that uses it is invoked? – Blrfl Oct 11 '16 at 22:51
  • @Blrfl It changes each time the function is called. – Tim Oct 12 '16 at 4:25
7

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 ....).

  • 1
    Thank you, I was actually a bit expecting this kind of answer, i.e. keep it statically allocated so as to be sure I don't end up with a stack overflow. Unfortunately I have not a recent GCC compiler and the code isn't small. – Tim Oct 11 '16 at 14:59
  • Can't you get (perhaps by compiling GCC from its source code) a GCC compiler for your platform? – Basile Starynkevitch Oct 11 '16 at 15:57
  • 1
    I already have one, it's just really old. Working on a new one is not on my scope, nor would it fit in my schedule. But sure, some things would be easier with up to date tools. – Tim Oct 11 '16 at 15:59
  • 3
    Asking your boss to get you a newer GCC (either by providing you with up to date binary tools, or by giving you time for recompilation of GCC) is IMHO worthwhile, because quite probably newer GCC would optimize slightly better (do you know about gcc -flto -Os ?) and you might gain some memory.... – Basile Starynkevitch Oct 11 '16 at 18:18
  • 1
    It's on track but that won't come before a while. I already use -Os on other systems with more recent toolchains, but I wasn't aware of this -flto parameter, thanks for pointing it out. (Note that I've done a few tests with GCC -Os and -O1-3 parameter a few weeks ago on GCC 5.4.1 and the RAM was the same all the time. The FLASH and the MCU running time were different though. That was not on the same MCU as the one I mention in this Q/A) – Tim Oct 12 '16 at 6:51
6

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.

4

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.

1

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.

  • 1
    I have also done this in the past but my question was more about the problems I could face if I put this on the stack, not really about the alternatives to RAM when we're short of it. Thanks for answering anyway – Tim Oct 13 '16 at 4:08
1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.