`std::string` allocations are my current bottleneck - how can I optimize with a custom allocator?

后端 未结 6 1903
半阙折子戏
半阙折子戏 2021-02-04 06:44

I\'m writing a C++14 JSON library as an exercise and to use it in my personal projects.

By using callgrind I\'ve discovered that the current bottleneck

6条回答
  •  别跟我提以往
    2021-02-04 06:54

    By default, std::string allocates memory as needed from the same heap as anything that you allocate with malloc or new. To get a performance gain from providing your own custom allocator, you will need to be managing your own "chunk" of memory in such a way that your allocator can deal out the amounts of memory that your strings ask for faster than malloc does. Your memory manager will make relatively few calls to malloc, (or new, depending on your approach) under the hood, requesting "large" amounts of memory at once, then deal out sections of this (these) memory block(s) through the custom allocator. To actually achieve better performance than malloc, your memory manager will usually have to be tuned based on known allocation patterns of your use cases.

    This kind of thing often comes down to the age-old trade off of memory use versus execution speed. For example: if you have a known upper bound on your string sizes in practice, you can pull tricks with over-allocating to always accommodate the largest case. While this is wasteful of your memory resources, it can alleviate the performance overhead that more generalized allocation runs into with memory fragmentation. As well as making any calls to realloc essentially constant time for your purposes.

    @sehe is exactly right. There are many ways.

    EDIT:

    To finally address your second question, strings using different allocators can play nicely together, and usage should be transparent.

    For example:

    class myalloc : public std::allocator{};
    myalloc customAllocator;
    
    int main(void)
    {
      std::string mystring(customAllocator);
      std::string regularString = "test string";
      mystring = regularString;
      std::cout << mystring;
    
      return 0;
    }
    

    This is a fairly silly example and, of course, uses the same workhorse code under the hood. However, it shows assignment between strings using allocator classes of "different types". Implementing a useful allocator that supplies the full interface required by the STL without just disguising the default std::allocator is not as trivial. This seems to be a decent write up covering the concepts involved. The key to why this works, in the context of your question at least, is that using different allocators doesn't cause the strings to be of different type. Notice that the custom allocator is given as an argument to the constructor not a template parameter. The STL still does fun things with templates (such as rebind and Traits) to homogenize allocator interfaces and tracking.

提交回复
热议问题