使用boost :: singleton_pool时处理std :: string / std :: vector成员变量

时间:2012-05-08 14:27:13

标签: c++ memory-management boost-pool

我正在编写一个性能关键型应用程序,我在其中创建大量类似类型的对象来下订单。我使用boost::singleton_pool来分配内存。最后我的班级看起来像这样。

    class MyOrder{
    std::vector<int> v1_;
    std::vector<double> v2_;

    std::string s1_;
    std::string s2_;

public:
    MyOrder(const std::string &s1, const std::string &s2): s1_(s1), s2_(s2) {}

    ~MyOrder(){}

    static void * operator new(size_t size); 
    static void operator delete(void * rawMemory) throw();
    static void operator delete(void * rawMemory, std::size_t size) throw();

};

struct MyOrderTag{};
typedef boost::singleton_pool<MyOrderTag, sizeof(MyOrder)> MyOrderPool; 

void* MyOrder:: operator new(size_t size)
{
    if (size != sizeof(MyOrder)) 
        return ::operator new(size);

    while(true){
        void * ptr = MyOrderPool::malloc();
        if (ptr != NULL) return ptr;

        std::new_handler globalNewHandler = std::set_new_handler(0);
        std::set_new_handler(globalNewHandler);

        if(globalNewHandler)  globalNewHandler();
        else throw std::bad_alloc();

    }
}

void MyOrder::operator delete(void * rawMemory) throw()
{
    if(rawMemory == 0) return; 
    MyOrderPool::free(rawMemory);
}

void MyOrder::operator delete(void * rawMemory, std::size_t size) throw()
{
    if(rawMemory == 0) return;
    if(size != sizeof(Order)) {
        ::operator delete(rawMemory);
    }
    MyOrderPool::free(rawMemory);
}

我最近发布了question关于使用boost :: singleton_pool的性能优势。当我比较boost::singleton_pool和默认分配器的性能时,我没有获得任何性能优势。当有人指出我的类有std :: string类型的成员,其分配不受我的自定义分配器的控制时,我删除了std :: string变量并重新进行了测试。这次我注意到了相当大的性能提升。

  1. 现在,在我的实际应用中,我无法摆脱时间std :: string和std :: vector的成员变量。我应该在我的std :: string和std :: vector成员变量中使用boost::pool_allocator吗?

  2. boost :: pool_allocator从底层std :: singleton_pool分配内存。如果不同的成员变量(我的MyOrder类中有多个std :: string / std :: vector类型。重要的是。我还使用了除MyOrder以外的类的池,其中包含std :: string / std :: vector类型作为成员)使用相同的内存池?如果是这样,我如何确保他们以某种方式做?

2 个答案:

答案 0 :(得分:2)

  
      
  1. 现在,在我的实际应用中,我无法摆脱时间std :: string和std :: vector的成员变量。我应该在我的std :: string和std :: vector成员变量中使用boost :: pool_allocator吗?
  2.   

我从未研究过boost的那一部分,但是如果你想改变字符串分配内存的位置,你需要在编译时将不同的分配器传递给std::basic_string<>。没有其他办法。但是,您需要注意其缺点:例如,此类字符串将不再分配给std::string。 (虽然使用c_str()会起作用,但可能会造成很小的性能损失。)

  
      
  1. boost :: pool_allocator从底层std :: singleton_pool分配内存。如果不同的成员变量(我的MyOrder类中有多个std :: string / std :: vector类型。重要的是。我还使用了除MyOrder以外的类的池,其中包含std :: string / std :: vector类型作为成员)使用相同的内存池?如果是这样,我如何确保他们以某种方式做?
  2.   

池的重点是将多个对象放入其中。如果它只是一个,你就不需要一个游泳池。所以,是的,您可以将几个对象放入其中,包括几个std::string对象的动态内存。

然而,这是否会让你获得任何性能提升还有待观察。您使用池是因为您有理由认为它比通用分配器更快(而不是使用它,例如,从特定区域分配内存,如共享内存)。通常这样的池更快,因为它可以对内部分配的对象的大小进行假设。这对于你的MyOrder类来说确实如此:它的对象总是具有相同的大小,否则(较大的派生类)你不会在池中分配它们。
std::string的情况有所不同。使用动态分配字符串类的重点是它适应任何字符串长度。所需的内存块大小不同(否则你可能只是char数组)。我认为池分配器没有足够的空间来改进通用分配器。


旁注:您的重载operator new()会返回调用全局值的结果,但您的operator delete只会将任何内容传递到该池的free()。这对我来说似乎很可疑。

答案 1 :(得分:1)

在您的类中使用std::string / std::vector的自定义分配器可以正常工作(假设分配器是正确的) - 但只有性能测试才能看到您是否真的看到它带来任何好处。

或者,如果你知道std::string / std::vector会有上限,你可以在std::array周围实现一个瘦包装(如果没有c,可以实现普通数组) ++ 11)这使它成为替代品。

即使大小无限制,如果大多数值的某个大小小于,您可以通过分配您的池,将上面基于std::array的实现扩展为可扩展的分配器,如果他们填满。