Search code examples
c++cmemoryallocation

C/C++ memory allocation chunkwise


Given the following situation, what is the most appropriate, platform-independent approach with respect to space/time consumption:

(1) At a given point in time the total size of a set of objects is known. Thus, the required memory could be allocated in one beat.

(2) The memory ownership needs to be distributed to each single object and the time of free-ing (deallocation) is undetermined.

My adhoc approach would be some type of reference counting on the allocated chunk of memory. Any time an object is free-ed the reference count decreases. When its zero the big chunk is freed.

Is there any pattern or common practice that would be more appropriate?


Solution

  • The given situation is not sufficient to determine the "best" approach.

    (1) At a given point in time the total size of a set of objects is known. Thus, the required memory could be allocated in one beat.

    If all the allocation happens on the initial part of the program, then this fact does not help us (unless it is crucial to speed up the boot time). This doesn't help either if the program frequently destroys and create new objects because the memory allocators never release its heap memory back to the OS anyhow; it just releases it for future own usage.

    The only case when this information is helpful is when all the allocation and deallocation of objects that occur during the lifetime of the program is of the same object type. In that case, a memory pool implementation will improve performance because finding the next available slot for allocation is always O(1). Here is an implamantion for example (source).

    If you also know the total size of objects for each object type, then multiple memory pools will also be very useful. If that is not the case, then you can always round up all the objects to the maximal object size and improve performance (using memory pool) on the account of wasted memory.

    (2) The memory ownership needs to be distributed to each single object and the time of free-ing (deallocation) is undetermined.

    Handling objects lifetime is hard and the best approach depends on these 3 questions:

    • How many references a single object have?
    • How many times does this object is passed from hand to hand?
    • Does your object's graph contain cycles?

    If the answers to these questions are "A couple, not much and no", then std::shared_ptr<> might be very helpful. However, if the number of references is not that small or the object is constantly transferred from hand to hand, then reference counting might induce heavy overhead in accounting for the references at each transfer of hand. If you have cycles in your object's graph, then memory leaks will occur. On such case, garbage collection solution will most likely have better performance and will be easier to manage (see Boeham's implementation for C and C++).

    My adhoc approach would be some type of reference counting on the allocated chunk of memory. Any time an object is free-ed the reference count decreases. When its zero the big chunk is freed.

    Given the fact that free() does not really free the memory back to the OS, I don't see any benefit from that approach. You will just have more managing overhead without gaining any performance. You didn't mention in your question the need to free back memory to the OS so I guess this is not an issue.

    Is there any pattern or common practice that would be more appropriate?

    The most significant improvement you can achieve is by eliminating the need to use the build in memory management as it is designed for general purpose. It takes everything into account and thus has, relatively, poor performance. For example, managing synchronization between threads.

    If you don't use more than one thread and the memory pool solutions are applicable to you, then use them; they will probably have the best performance and they are quite simple. If memory pool is not applicable, and/or you are using many threads in your program, then I'll go for one of the many alternative memory allocators out there. A good multithreaded memory allocator I know of is Hoard.