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.