Coding Horror: The Sad Tragedy of Micro-Optimization Theater
codinghorror.com
codinghorror.com
Joel originally described the "Shlemiel" case when referring to strings in C not having a length stored in them, and needing to use strlen to walk the string to find the length. The Shlemiel problem comes up when you use strcat in a loop, since each strcat call needs to recalculate the length of the loop, which takes longer as the string gets longer.
The problem with concatenating strings is not a length issue, but a memory issue. In order to concatenate a string in C# or C++ using built in string classes, the location to store the new resulting string has to be allocated and the two strings have to copied into this new location. The allocation does not take up a trivial amount of time, and reallocating memory over and over again for each time you concatenate a string is bad practice. There is still a bit of "Shlemiel" since you have to keep copying your existing string, which takes a larger amount of time as the string gets longer, but you have to take in consideration the allocation, which wasn't present in the original problem that the "Shlemiel" story described.
The schlemiel problem still exists when doing '+=' in a loop. Each copy requires some code to walk the length of both sides of the operator, same as strlen in Joel's example. The loop is an O(n^2) operation, even if it has a smaller constant on it than a memcpy(src, dest, strlen(src)).
It's "Schlemiel", but with different constants attached. For big enough N the O(1) or O(log(n)) of the allocations lose importance making the entire thing O(n^2) just like "Schlemiel".
The cost of allocating memory in .NET (and probably other GC environments) is basically equivalent to the cost of incrementing a pointer, which is to say, basically free. The reason is because the .NET garbage collector periodically "packs together" objects in memory, so the memory allocation algorithm essentially becomes:
result = _freeMemoryPtr;
_freeMemoryPtr += numBytesToAllocate;
return result;
... in other words, since objects in memory are periodically "packed together" by the GC, there isn't a lot of memory fragmentation, so the allocator can simply allocate from the end of the heap. It doesn't need to try to find a "large enough free block" within fragmented memory, because memory isn't fragmented.At least, that is my understanding. I could be wrong because I haven't investigated this thoroughly yet.
http://en.wikipedia.org/wiki/Garbage_collection_(computer_sc...
I got a 7x performance improvement in a performance-critical component at Arbor Networks within a couple weeks of starting there just by profiling, finding malloc/free at the top of the profile, and switching to an arena allocator. I have other malloc stories, but that's the simplest. I've learned to fear malloc.
A micro-summary to illustrate:
1. I love strings.
2. You don't want to concatenate strings in (large) loops.
3. You already knew that, at least if you're a decent programmer.
4. Analysis of various methods of concatenating strings in loops.
5. Reveal that the methods don't matter.
6. It's bad to worry about micro-optimizations like the best way to concatenate strings in a loop.
7. Just avoid obvious mistakes like concatenating strings in loops.
8. Otherwise, don't worry about micro-optimization. Instead, focus on your real goal: writing better code.
Maybe it's me, but this article felt disjointed.
But hardly any web framework I've ever used will even permit this, all insisting on being handed one big string to ship out to the user. Sigh.
8678ms for concatenation Vs 19ms for stringbuilding
It seems like he sets up a straw man string concatenation problem and then tears it down in a pointless argument.
Here's a good overview of all options available to ASP.NET MVC: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/01...