Go Down

Topic: The HATRED for String objects - "To String, or not to String" (Read 13 times) previous topic - next topic

Nick Gammon

In your example the stack is incremented* by 12 (10 plus 2 for the int) to make room for those variables. They are thus uninitialized because they have whatever was on the stack. When loop exits that stack space is reclaimed.

If you make them global the stack doesn't get altered but you have 12 bytes less available for the stack because they have to go somewhere.

The stack and heap share the same piece of memory (RAM) starting at wherever your global variables end. The heap grows upwards and the stack grows downwards from the top of memory. If they happen to collide: trouble!

* decremented really, because the stack grows downwards.

GoForSmoke

#16
Sep 27, 2012, 12:33 pm Last Edit: Sep 27, 2012, 12:35 pm by GoForSmoke Reason: 1
I don't know if there's any time savings but a global gets allocated once while or making non-static locals or passing a load of parameters to a function happens over and over.

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Nick Gammon

True, a stack-based variable will take a couple of machine cycles to reserve the extra stack. If you only ever need the one copy, a global (or static) variable would suit your needs.

majenko

Ok, guys.  For your reference, let me clear up how memory works ;)  (for those who know already, this is for those who don't.)

There are basically two types of "dynamic" memory:  the "stack", and the "heap".

The stack can be thought of like a pile of coins.  Coins are put on to the pile in order, and then removed afterwards in reverse order.

Any "local" variables, along with any variables passed to functions, are placed on the stack, used within the function they are defined in, and then removed from the stack again.

The stack starts at the top of the memory space, and grows downwards.

Then there is the "heap".  This is more like a mound of coins.  Coins can be put into the mound wherever they will fit.  If there is no room inside the mound for them, then they are dropped on the top of the mound.  Coins can be pulled out from anywhere in the mound.  The same goes for variables.  These are all "dynamically allocated" variables.  Anything that uses "malloc()" or "free()", and any classes or functions which use these functions within themselves.

The heap is located at the bottom of the memory area.

The two main issues with the heap are memory leaks and memory fragmentation.

Memory leaks occur when some function places coins into the mound, and then forgets that it put them there, so they never get taken out again.  Variables created in the heap must be removed after use, or the heap will just grow and grow and grow.

Memory fragmentation occurs when small variables are removed from the heap to be replaced by larger variables.  The space left by the small variable is too small to accept the larger variable, so the larger variable is instead placed on the top of the heap, causing the heap to grow.  This most often occurs when working with strings and you want to add something to the end of a string (concatenate) or join two strings together.

As the heap gets more and more fragmented and grows bigger and bigger over time, and as more and more local variables get pushed into the stack, there is a big risk that the heap and the stack will both grow so big that they meet in the middle.  When this happens you have problems.  Big problems.  This is when crashes occur.

You can get "memory de-fragmentation" programs for the PC which effectively re-arrange the heap to remove the holes in it.  This makes programs run faster, as they can allocate bigger chunks of memory, and helps to reduce the overall size of the heap.  Quite useful.  There is nothing (as far as I have seen) like it for micro-controllers - mainly due to the lack of space in the first place ;)

So, the issue with the String class isn't with the String class itself - it's a very useful class (in the right situations).  The issue is with dynamic allocated memory causing fragmentation in the heap, which overflows and crashes into the stack.

So yes, a fix to "free()" will improve things, but on a small micro-controller with very limited RAM space dynamic memory allocation in itself is something to be shunned whenever possible.
Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

PaulS

Quote
So, the issue with the String class isn't with the String class itself - it's a very useful class (in the right situations).  The issue is with dynamic allocated memory causing fragmentation in the heap, which overflows and crashes into the stack.

Part of the problem IS with the String class itself. When you want to append one character to an existing String, the length of the new String is the length of the old String plus the length of the String to append. That amount of space is allocated, and the old String is copied there, then the String to be appended is tacked on, then the old String's space is freed.

Append another character, and the whole process is repeated, because the String has no room to grow.

On other platforms, extra space is allocated, so that there is some room to grow. Perhaps 10 extra bytes, so you can add 10 characters, before a malloc/copy/free operation is required again.

Go Up