我有一个Visual Studio 2008 C++应用程序,我正在为标准容器使用自定义分配器,以便它们的内存来自内存映射文件而不是堆.此分配器用于4种不同的用例:
std::vector< SomeType, MyAllocator< SomeType > > foo;std::basic_string< char, std::char_traits< char >, MyAllocator< char > > strn;我需要能够为这些中的每一个分配大约32MB的总和.
分配器使用std::map指向分配大小的指针跟踪内存使用情况.typedef std::map< void*, size_t > SuperBlock;每个SuperBlock代表4MB内存.
std::vector< SuperBlock >如果一个SuperBlock没有足够的空间,则有其中一个.
用于分配器的算法如下:
不幸的是,一段时间后,第2步可能变得非常缓慢.随着对象的复制和临时变量的破坏,我得到了很多碎片.这导致在存储器结构内进行大量深度搜索.碎片存在问题,因为我使用的内存有限(请参阅下面的注释)
任何人都可以建议改进这种算法来加速这个过程吗?我需要两个单独的算法(1个用于固定大小的分配,1个用于字符串分配器)?
注意:对于那些需要理由的人:我在Windows Mobile中使用此算法,其中Heap有32MB的进程槽限制.所以,通常std::allocator不会削减它.我需要将分配放在1GB大内存区域中以获得足够的空间,这就是它的作用.
20.6.9:
void deallocate(pointer p, size_type n);
Run Code Online (Sandbox Code Playgroud)
如果n不等于作为第一个agrgument传递给返回的allocate调用的值,会发生什么p?不解除分配?扔std::bad_alloc?...
编辑: 我实际上对"应该发生什么"的意思是:在自定义实现中抛出或断言是否可以?
在C++ 11中,std :: vector具有构造函数vector(size_type n),该构造函数将默认构造n项目,可以使用默认的可构造,可移动,不可复制的类.
但是,与其他所有向量构造函数不同,没有采用分配器的变体,我采用了以下方法:
// Foo is default constructible and moveable, but not copyable
const int n = 10; // Want 10 default constructed Foos
std::vector<Foo, CustomAllocator> foos(allocator);
foos.reserve(n);
for (int i = 0; i < n; ++i)
foos.emplace_back();
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来实现这一目标?vector(size_type n, const Allocator& alloc)标准中是否省略了具体原因?
我注意到Linux中有关内存使用情况(RES)的一些有趣行为top.我附加了以下程序,它在堆上分配了几百万个对象,每个对象都有一个大约1千字节的缓冲区.指向这些对象的指针由a std::list或a 跟踪std::vector.我注意到的有趣行为是,如果我使用a std::list,则报告的内存使用率top在睡眠期间永远不会改变.但是,如果我使用std::vector,那些睡眠期间内存使用率将降至接近0.
我的测试配置是:
Fedora Core 16
内核3.6.7-4
g ++版本4.6.3
我已经知道的:
1.std :: vector将根据需要重新分配(加倍大小).
2. std :: list(我相信)一次分配它的元素1.
std :: vector和std :: list默认使用std :: allocator来获取它们的实际内存
4.程序没有泄漏; valgrind宣称不可能泄漏.
令我困惑的是:
1.std :: vector和std :: list都使用std :: allocator.即使std :: vector正在进行批量重新分配,std :: allocator也不会以几乎相同的方式将内存分发给std :: list和std :: vector?毕竟这个程序是单线程的.
2.我在哪里可以了解Linux内存分配的行为.我听说过关于Linux保持RAM分配给进程的声明,即使它释放了它,但我不知道这种行为是否得到保证.为什么使用std :: vector会对这种行为产生如此大的影响?
非常感谢您阅读本文; 我知道这是一个相当模糊的问题.我在这里寻找的'答案'是这个行为是'定义'还是我可以找到它的文档.
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <list>
#include <iostream>
#include <memory>
class Foo{
public:
Foo()
{
data = …Run Code Online (Sandbox Code Playgroud) C++ 11标准在通用容器要求中有以下几行.
(23.2.1 - 3)
对于受此子条款影响且声明allocator_type的组件,存储在这些组件中的对象应使用allocator_traits :: construct函数构造,并使用allocator_traits :: destroy函数(20.6.8.2)进行销毁.这些函数仅针对容器的元素类型调用,而不是针对容器使用的内部类型调用
(23.2.1 - 7)
除非另有说明,否则本节中定义的所有容器都使用分配器获取内存
是否真的,容器使用的所有内存都是由指定的分配器分配的?因为标准说内部类型不是用allocator_traits :: construct构造的,所以应该对operator new进行某种调用.但是标准也说这个子句中定义的所有容器都使用分配器来获取内存,在我看来这意味着它不能是普通的新运算符,它必须是放置新的运算符.我对么?
让我举个例子,为什么这很重要.
假设我们有一个类,它包含一些已分配的内存:
#include <unordered_map>
#include <iostream>
#include <cstdint>
#include <limits>
#include <memory>
#include <new>
class Arena
{
public:
Arena(std::size_t size)
{
size_ = size;
location_ = 0;
data_ = nullptr;
if(size_ > 0)
data_ = new(std::nothrow) uint8_t[size_];
}
Arena(const Arena& other) = delete;
~Arena()
{
if(data_ != nullptr)
delete[] data_;
}
Arena& operator =(const Arena& arena) = …Run Code Online (Sandbox Code Playgroud) 在下面的代码中,每10个整数的许多向量构造有60%的几率,或者现有的向量被删除,有40%的几率.因此,会有很多调用new/malloc和delete.由于所有这些载体类型vector<int>,可以在这里自定义分配器的帮助,以减少电话new和delete,从而提高性能?这个想法是删除的矢量的空间可以由新构造的空间重用.这样的分配器怎么样?
注意:这个问题是关于分配器,它减少了对new和的调用delete.
#include <iostream>
#include <vector>
#include <random>
using namespace std;
int main()
{
// Random generator and distribution
mt19937 gen(123456);
uniform_real_distribution<> dis01(0., 1.);
// Make or delete 10E6 vectors.
vector< vector<int> > v; //the inner vectors will make many calls to new and delete
v.reserve(10E5); //assume some size.
for(int i=0; i<10E6; ++i)
{
if(dis01(gen)<0.6) // if true: make new sub-vector
{
v.emplace_back(); //new sub-vector
v.back().reserve(10);
for(int k=0; k<10; ++k) …Run Code Online (Sandbox Code Playgroud) 这是自定义分配器中的内存布局: -
^ toward less address
....
Header [size=16 alignment=4 ] ....(1)
some waste space A [size=A (unknown) ]
content [size="SIZE" alignment="ALIGN"] ....(2)
some waste space B [size=B (unknown) ]
Header [size=16 alignment=4 ] ....(3)
....
v toward more address
Run Code Online (Sandbox Code Playgroud)
Header事先并不知道确切的地址.
但是,我知道: -
every Header address % 4 == 0 from (1,3)
"content"%ALIGN == 0 from (2)
Run Code Online (Sandbox Code Playgroud)
如何确定最小字节数A+content+B使得所有内容(1和2和3)始终正确对齐?
//return maximum size of A+content+B that make the allocation always safe
int wasteA_content_wasteB(int SIZE,int ALIGN){
//??? …Run Code Online (Sandbox Code Playgroud) 我是新手,我想知道boost :: pool库如何帮助我创建自定义内存分配器.我有两个struct对象向量.第一个向量是结构类型A,而第二个向量是结构类型B.我如何重用分配给第一个向量的内存到第二个向量.
我分析了我的程序,发现从标准分配器更改为自定义一帧分配器可以消除我最大的瓶颈。
这是一个虚拟片段(coliru链接):-
class Allocator{ //can be stack/heap/one-frame allocator
//some complex field and algorithm
//e.g. virtual void* allocate(int amountByte,int align)=0;
//e.g. virtual void deallocate(void* v)=0;
};
template<class T> class MyArray{
//some complex field
Allocator* allo=nullptr;
public: MyArray( Allocator* a){
setAllocator(a);
}
public: void setAllocator( Allocator* a){
allo=a;
}
public: void add(const T& t){
//store "t" in some array
}
//... other functions
};
Run Code Online (Sandbox Code Playgroud)
但是,我的一帧分配器有一个缺点-用户必须确保由一帧分配器分配的每个对象都必须在时间步结束时删除/释放。
这是一个用例示例。
我使用一帧分配器在Physics Engine中存储(碰撞检测的重叠表面;Wiki链接)的临时 …