Tuesday, January 17, 2012

Memory Management and Concurrency in C++

Despite the flurry of activity from the Boost and C++11 standards committee, two crucial things remain quite challenging: efficient memory management and concurrency. What started me down this train of thought was some good old code reading. I encountered plain old vectors of pointers. There are apparently a handful of alternatives to this. Boost implements ptr_vector that keeps track of the lifetimes of all its elements as a unit. vector<shared_ptr> is another possibility. The core of the problem is that since vectors' underlying representation is a pointer, and one cannot get a pointer to a reference (the assumption being one wanted the efficiency of reference-passing but with the convenience of STL containers).

More after the jump

The problem is that even with the variety of smart pointers out there including reference counting shared_ptrs and auto_ptrs, memory management is still really hard to get right in C++. Compatibility with libraries remains an issue because ultimately if a library uses regular pointers, you'll have to be dragged into work with them too. Performance is the other huge issue. Reference counting is really expensive. One contention post has shared_ptrs degrading performance up to 10x (slowdown) versus a comparable OCaml garbage collected version. C++ may be usually close to the metal, but referencing counting is expensive no matter how you dice it. Concurrency is yet another issue. Many common libraries aren't thread-safe. STL containers

One solution is region-based memory management. The Boost library does included facilities for memory pools, but this only works with homogeneous sized objects whereas regions are more general, capable of dealing with objects of heterogeneous sizes. Still, the Boost library is pretty useful if you have a whole lot of a small objects (where the size of the object makes a reference count a huge overhead) which can be deallocated together. In the Boost case, the deallocation must be manually done. For region-based memory management, there are both explicit (i.e., manual) and inference-based (i.e., automatic) variations.

The other solution, perhaps more general purpose and less invasive, is advanced garbage collection techniques. Garbage collectors have evolved considerably since the days when poorly performing stop-the-world collectors were the norm. Since then, researchers have demonstrated that garbage collection can be parallelized and improved considerably. Languages tailored for high-performance applications such as Lua have adopted correspondingly high-performance garbage collectors such as incremental collectors.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.