9

我正在编写一个性能关键的应用程序,在该应用程序中我创建了大量类似类型的对象来下订单。我正在使用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);
}

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

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

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

4

2 回答 2

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

我从来没有研究过 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 类型的类使用池作为成员)使用相同的内存池?如果是这样,我如何确保他们以一种或另一种方式做事?

池的全部意义在于将多个对象放入其中。如果它只是一个,你就不需要一个游泳池。所以,是的,你可以把几个对象放进去,包括几个std::string对象的动态内存。

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


附带说明:您的重载operator new()返回调用全局结果的结果,但是您operator delete只是将任何东西传递到该池的free(). 这对我来说似乎很可疑。

于 2012-05-08T19:43:16.903 回答
1

Using a custom allocator for the std::string/std::vector in your class would work (assuming the allocator is correct) - but only performance testing will see if you really see any benefits from it.

Alternatively, if you know that the std::string/std::vector will have upper limits, you could implement a thin wrapper around a std::array (or normal array if you don't have c++11) that makes it a drop in replacement.

Even if the size is unbounded, if there is some size that most values would be less than, you could extend the std::array based implementations above to be expandable by allocating with your pooled allocator if they fill up.

于 2012-05-17T18:54:20.417 回答