提升池分配器比新的慢
Boost pool allocator slower than new
本文关键字:分配器 更新时间:2023-10-16
所以我基于提升池创建了这个容器分配器memory_pools
类:
memory_pools.hpp
#ifndef MEMORY_POOL_HPP
# define MEMORY_POOLS_HPP
// boost
# include <boost/pool/pool.hpp>
# include <boost/unordered_map.hpp>
template<typename ElementType>
class memory_pools
{
public:
template <typename>
friend class memory_pools;
private:
using pool = boost::pool<>;
public:
using value_type = ElementType;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = pool::size_type;
using difference_type = pool::difference_type;
public:
template<typename OtherElementType>
struct rebind
{
using other = memory_pools<OtherElementType>;
};
public:
memory_pools();
template<typename SourceElement>
memory_pools(const memory_pools<SourceElement>&);
public:
pointer allocate(const size_type n);
void deallocate(const pointer ptr, const size_type n);
template<typename... Args>
void construct(pointer, Args...);
void destroy(pointer);
public:
bool operator==(const memory_pools&);
bool operator!=(const memory_pools&);
private:
using pools_map = boost::unordered_map<std::size_t, std::shared_ptr<pool>>;
private:
std::shared_ptr<pools_map> pools_map_;
std::shared_ptr<pool> pool_;
};
# include <memory_pools.ipp>
#endif
内存池.ipp
#ifndef MEMORY_POOLS_IPP
# define MEMORY_POOLS_IPP
template<typename ElementType>
memory_pools<ElementType>::memory_pools()
:
pools_map_(std::make_shared<pools_map>
(pools_map
{
std::make_pair
(sizeof(ElementType),
make_shared<pool>(sizeof(ElementType)))
})),
pool_(pools_map_->at(sizeof(ElementType)))
{
}
template<typename ElementType>
template<typename SourceElement>
memory_pools<ElementType>::memory_pools
(const memory_pools<SourceElement>& rebinded_from)
:
pools_map_(rebinded_from.pools_map_),
pool_(pools_map_->insert
(std::make_pair(sizeof(ElementType),
make_shared<pool>(sizeof(ElementType)))).first->second)
{
}
template<typename ElementType>
typename memory_pools<ElementType>::pointer memory_pools<ElementType>::allocate
(const size_type n)
{
pointer ret = static_cast<pointer>(pool_->ordered_malloc(n));
if ((!ret) && n)
throw std::bad_alloc();
return (ret);
}
template<typename ElementType>
void memory_pools<ElementType>::deallocate
(const pointer ptr, const size_type n)
{
pool_->ordered_free(ptr, n);
}
template<typename ElementType>
template<typename... Args>
void memory_pools<ElementType>::construct(pointer ptr, Args... args)
{
new (ptr) ElementType(std::forward<Args>(args)...);
}
template<typename ElementType>
void memory_pools<ElementType>::destroy(pointer ptr)
{
ptr->~ElementType();
}
template<typename ElementType>
bool memory_pools<ElementType>::operator==(const memory_pools& rhs)
{
return (pools_map_ == rhs.pools_map_);
}
template<typename ElementType>
bool memory_pools<ElementType>::operator!=(const memory_pools& rhs)
{
return (pools_map_ != rhs.pools_map_);
}
#endif
然后当我用测试它时
#include <memory_pools.hpp>
int main(void)
{
using pools_type = memory_pools<std::pair<const int, int>>;
pools_type pools;
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>, pools_type> map;
//boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>> map;
for (unsigned int i = 0; i < 20000; ++i)
{
map[i] = i + 1;
}
return (0);
}
在macOSX 10.10上使用clang3.5,我得到了:
$ time ./a.out
real 0m1.873s
user 0m1.850s
sys 0m0.009s
而当我启动时:
#include <memory_pools.hpp>
int main(void)
{
using pools_type = memory_pools<std::pair<const int, int>>;
pools_type pools;
//boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>, pools_type> map;
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>> map;
for (unsigned int i = 0; i < 20000; ++i)
{
map[i] = i + 1;
}
return (0);
}
我有:
$ time ./a.out
real 0m0.019s
user 0m0.016s
sys 0m0.002s
问题
使用提升池的内存分配是应该那么慢,还是我的测试由于某种原因无效?
编辑
在Careron的评论之后,我添加了-O3
和-DNDEBUG
标志,现在我有了:
$time ./a.out
real 0m0.438s
user 0m0.431s
sys 0m0.003s
对于memory_pools
版本,以及:
$ time ./a.out
real 0m0.008s
user 0m0.006s
sys 0m0.002s
对于标准分配器版本。
问题
问题仍然存在,速度变慢是正常的吗?
我从未使用过Boost的池代码,甚至从未阅读过它。但我确实对内存池有一些了解,我不希望你的测试中的内存池能胜过malloc。
要理解这一点,您必须首先了解malloc和free是如何实现的(如果您还没有)。这个问题的答案似乎提供了一个很好的总结:malloc()和free()是如何工作的?
对于malloc()
和free()
来说,内存碎片是一个难题,没有简单、快速的解决方案。但是,如果你能保证所有的分配都是相同的大小,那就容易多了:这就是内存池获胜的方式。但你的测试并不涉及太多的内存碎片,而且可能根本不会释放太多内存。因此,在这个测试中,malloc()
获胜,而pools失败。为了完善你的测试,你可能会混合一些删除,比如:
// Allocate 10,000 things
// Loop 10 times:
// Allocate 1,000 things
// Delete 1,000 things
说了这么多,如果你真的想知道为什么一段特定的代码会以这种方式运行,你应该对它进行分析。思考为什么一段代码会以某种方式运行的理论很有用,但你也必须测试你的理论。
相关文章:
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 将 std::allocate_shared 与多态资源分配器一起使用
- 尝试将lambda函数放在队列中时出现一般分配器错误(可能是与unique_ptr有关的错误)
- C++17 - 使用自定义分配器的节点提取/重新插入 - 适用于 clang++/libc++,但不适用于 libstd
- 使用 std::分配器在 constexpr 中进行默认初始化
- 使用不兼容的分配器复制分配无序列图
- C++:矢量分配器行为、内存分配和智能指针
- 是否可以使用分配器对象来释放另一个分配器分配的内存?
- 使用模板化分配器和对向量进行排序的函数
- C++ 中的分配器错误
- 基于浅树的数据结构的内存分配器,用于频繁分配和解除分配
- 通过引用传递向量是请求 std::分配器
- 为什么这个分配器不适用于"std::allocate_shared"?奇怪的模板替换错误
- 为什么 std::vector 使用 std::分配器而不是运算符 new 和 delete?
- C++自定义分配器大小参数作为模板参数会引发编译器错误
- 在分配器中销毁元素时,C++会导致双重释放<string>?
- C++17 和更新的 std::分配器是否适用于动态数量的自定义堆?
- c++ 中的自定义分配器,用于不调用secure_string实现
- 是否允许分配器构造和销毁成员函数从内部逻辑引发异常?
- 我可以对 std::array 使用自定义分配器来获取安全加密密钥吗?