【发布时间】:2013-11-07 06:26:39
【问题描述】:
我想创建一个对象池,但我希望它只在我的内存堆的特定段上分配内存。有没有办法使用 boost 来做到这一点?
【问题讨论】:
标签: c++ boost object-pooling
我想创建一个对象池,但我希望它只在我的内存堆的特定段上分配内存。有没有办法使用 boost 来做到这一点?
【问题讨论】:
标签: c++ boost object-pooling
Boost.Pool 的object_pool 允许用户通过提供UserAllocator 来控制池使用的内存。根据文档:
Pool 对象需要向系统请求内存块,然后 Pool 将其拆分成块分配给用户。通过为各种 Pool 接口指定
UserAllocator模板参数,用户可以控制这些系统内存块的分配方式。
Boost.Pool 仅提供使用new/delete 和malloc/free 的基本分配器。但是,如果可以编写分配器以在空闲存储的特定段中分配,那么object_pool 也可以配置为这样做。可能需要检查编译器和平台是否支持将免费存储中的分配限制到特定段。
这是一个基本示例,我忽略了一些细节以保持示例简单,并展示一个类型如何满足UserAllocator 的要求。在此示例中,boost::object_pool 将使用自定义分配器,该分配器使用预分配的静态内存。
#include <iostream>
#include <boost/array.hpp>
#include <boost/pool/object_pool.hpp>
namespace detail {
/// @brief Pre-allocated managed memory block.
template <std::size_t N>
class arena
{
public:
/// @brief Constructor.
arena()
: current_(&buffer_.front()), // Set current to start.
end_(current_ + N) // End sentinel.
{
std::cout << "arena memory range: "
<< static_cast<void*>(current_) << " - "
<< static_cast<const void*>(end_) << std::endl;
}
/// @brief Attempt to allocate memory from pre-allocated block.
///
/// @param n Count of bytes to allocate.
///
/// @param Non-zero if allocation is succesfull. Otherwise, zero.
char* allocate(std::size_t n)
{
// If there is no more memory, then return zero.
if ((current_ + n) > end_) return 0;
// Otherwise, return available memory and shift current.
std::cout << "arena allocating: "
<< static_cast<void*>(current_) << std::endl;
char* ptr = current_;
current_ += n;
return ptr;
}
void deallocate(char* p, std::size_t n)
{
// ...
}
private:
/// @brief Block of memory used for allocations.
boost::array<char, N> buffer_;
/// @brief Pointer to current allocation.
char* current_;
//// @brief End pointer sentinel.
const char* end_;
};
} // namespace detail
/// @brief Allocator that meets Boost.Pool's UserAllocator Concepts.
/// This allocator will allocate memory from a pre-allocated
/// block of static memory. Each instance of the template is
/// considered to be its own unique allocator, and thus has its
/// own memory.
template <std::size_t N>
class static_allocator
{
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char* malloc(const size_type n) { return arena_.allocate(n); }
static void free(char* p) { arena_.deallocate(p, 1); }
private:
static detail::arena<N> arena_;
};
template <std::size_t N>
detail::arena<N> static_allocator<N>::arena_;
/// @brief Helper type.
template <typename T, std::size_t N>
struct static_object_pool:
boost::object_pool<T, static_allocator<N * sizeof(T)> >
{};
/// Mockup object.
class Foo {};
int main()
{
static_object_pool<Foo, 128> pool;
Foo* a = pool.malloc();
std::cout << "a is at " << a << std::endl;
Foo* b = pool.malloc();
std::cout << "b is at " << b << " -- freeing b" << std::endl;
pool.free(b);
Foo* c = pool.malloc();
std::cout << "c is at " << c << std::endl;
}
还有输出:
arena memory range: 0x804b5a0 - 0x804b620
arena allocating: 0x804b5a0
a is at 0x804b5a0
b is at 0x804b5a4 -- freeing b
c is at 0x804b5a4
请注意,从object_pool::malloc() 返回的每个地址都在竞技场的内存范围内。此外,当 b 通过 pool.free(b) 释放时,内存 (0x804b5a4) 会在下一次 malloc() 用于 c 时立即被池重用。
【讨论】:
UserAllocator 的类型要求。我还稍微扩展了答案,因为最初我不清楚这个问题是在问关于控制 Boost.Pool 的分配方式还是实际分配本身。对于它的价值,我只能使用特定于实现的调用在固定地址嵌入式系统上分配到空闲存储中的特定段。