0

好的,我在使用boost::fast_pool_allocator.

我拥有的代码适用于对 的前几次调用fast_pool_allocator::allocate(1),但随后失败并显示以下消息:

Engine.exe 中 0x000000013fd0fe2d 处未处理的异常:0xC00000005:访问冲突读取位置 0x0000000000ffffff

调用堆栈:

Engine.exe!boost::simple_segregated_storage<unsigned __int64>::malloc()  Line 104
Engine.exe!boost::pool<boost::default_user_allocator_new_delete>::malloc()  Line 223 
Engine.exe!boost::singleton_pool<boost::fast_pool_allocator_tag,128,boost::default_user_allocator_new_delete,boost::details::pool::win32_mutex,32>::malloc()  Line 59
Engine.exe!boost::fast_pool_allocator<EventDataSize,boost::default_user_allocator_new_delete,boost::details::pool::win32_mutex,32>::allocate(const unsigned __int64 n)  Line 229
Engine.exe!IEventData::operator new(unsigned __int64 size)  Line 46
etc...  

有问题的 boost 代码行似乎是正确的,分配器存储机制将返回下一个空闲块,并将其从空闲块列表中删除

void * malloc()
{
  void * const ret = first;

  // Increment the "first" pointer to point to the next chunk
  first = nextof(first); // <--- This is the line that is failing.
  return ret;
}

我的代码如下所示:

class EventDataSize
{
private:
    U8 dummyField[128];
};

class IEventData
{    
public:    
    void* operator new(size_t size)
    {       
        void* ptr = boost::fast_pool_allocator<EventDataSize>::allocate(1);
        if (!ptr)
            throw std::bad_alloc();
        return ptr;
    }

    void operator delete(void* ptr)
    {
        boost::fast_pool_allocator<EventDataSize>::deallocate((EventDataSize*)ptr, 1);
    }

// etc...
}

如您所见,我试图将此类EventDataSize用作虚拟对象,以便为继承自的任何类IEventData分配相同的大小(例如 128 字节),从而允许池分配器与继承一起愉快地工作。

我在其他地方使用完全相同的模式来实现 operator new 与其他基类,他们似乎没有遇到同样的问题。

奇怪的是,如果我改变数组大小,EventDataSize::dummyField问题就消失了(或者至少它还没有出现),但我对这种不合标准的解决方案感到不舒服......我想知道为什么这个分配器正在做它正在做什么,我做错了什么,以及如何优雅地修复它!

4

2 回答 2

3

我意识到,因为我有另一个基类 IControl,使用相同的模式,并使用它自己的 ControlSize 虚拟对象(也是 128 字节),所以两个 fast_pool_allocators 都在后台使用相同的池对象。

然而,我的 IControl 子类之一大于 128 字节。因此它被分配没有问题,但随后覆盖了空闲块的池链接列表。

本质上,这正是 Oo Tiib 所说的问题,但转移到了稍微不同的代码部分。

正如 Oo Tiib 和 bish-bash-bosh 所示,我修复了这两个地方的代码,它就像一个魅力!

于 2012-09-10T17:31:20.497 回答
2

始终测试您的理论(无论它们是什么)是否成立。您似乎有一个理论认为 128 字节对于任何 IEventData 都足够好,所以您可以忽略大小?继续测试它:

void* operator new(size_t size)
{
    if ( size > sizeof( EventDataSize ) )
    {
       throw std::runtime_error("crappy idea, pal");
    }
    void* ptr = boost::fast_pool_allocator<EventDataSize>::allocate(1);
    if (!ptr)
        throw std::bad_alloc();
    return ptr;
}

对我来说,感觉可能有大于 128 字节的事件数据,所以它搞砸了池分配器池中的东西。

于 2012-09-08T21:01:18.383 回答