如何在不使指针无效的情况下增加缓冲区?

| 术语“池”和“缓冲区”在此处可以互换使用。 假设我有一个要在程序开始时分配的池,因为并非总是每次都调用ѭ0。 现在,我不想人为地限制池的大小,但是如果我重新分配一个更大的池,则所有指向旧池的指针都将失效,这当然不是很酷。 我想到的一种方法是“分页”
const int NUM_PAGES = 5;
char* pool[NUM_PAGES];
并分配一个新页面,而不是仅重新分配一个页面。这将使所有指针保持有效,但会使分页池的管理更加困难。另外,我将自己限制在页面数上,因此最后又限制了池的大小。 另一种方法是从我的分配函数返回的指针映射到真实内存空间的指针。这将使所有旧指针保持有效,但会占用更多内存,并且我需要编写一个智能指针以从执行映射的分配函数中返回。 还有哪些其他可能的方法可以实现我想要的?在上述示例实现中我错过了哪些(缺点)优势?     
已邀请:
您正在谈论的东西让我想起了2英镑。我不确定是否可以原样使用
std::deque
,还是只需要使用其基本设计来实现某种分配器即可。     
扩展到分页的“池”概念上,如果将页面存储为链接列表怎么办? 要从池中分配新数据,您只需要有权访问列表的顶部\“页面\”,所以O(1)。如果您需要增加池的总大小,请分配一个新页面并将其推到列表的开头,也就是O(1)。 对于池分配器,我基本上使用相同的想法,但是对最近释放的项使用“免费列表”。 编辑: 根据您的评论,如果您还想使用释放的数据,则还可以存储一个空闲列表,也可以存储为链接列表。因此,当您解除分配数据时,会将指针和大小标记推送到空闲列表中。从池中分配数据时,首先检查是否可以使用空闲列表中的任何项目,如果不能,则从池中进行分配。 标准内存管理器通常已经做过这样的事情,因此这种方法并不总是更好。具体来说,我通常仅在分配的项目大小相同时才使用这种类型的自定义分配器(这样,自由列表的遍历为O(1)!)。一个自定义std :: list分配器就是一个例子。 希望这可以帮助。     
考虑使用升压池     
当然,一个问题是为什么要这样困扰自己? 您说您希望避免
new
的开销,但是为什么不选择更好的
new
实现呢?例如,
tcmalloc
jemalloc
通常是多线程应用程序的很好竞争者。 实际上,您尝试创建的内容与编写自定义
malloc
/
new
实现非常相似。因此,如果您真的不想使用经过验证的实现,那么您将从那些做过的事情中受益。 我个人的兴趣倾向于使用BiBOP策略(大书页)来解决碎片问题。想法是每个分配大小都有一个专用池,因此一个简单的自由列表(与分配交错)就足够了(不需要合并)。通常,只要请求的大小小于页面大小(我已经看到使用4KB)并且任何更大的东西都会自己分配(在几个页面中),就可以这样做。丢弃的页面被回收。 我主要感兴趣的是,使用BiBOP可以很容易地维护间隔树的地址范围->页面标题,从而从(可能是)内部元素(例如属性)的地址确定对象的完整大小,这对于垃圾收集很有用(请参考以下步骤)。 对于多线程分配,ѭ6和ѭ7使用两种不同的方法:
jemalloc
使用每个线程池:固定数量的线程/线程池很好,但是使创建线程的过程更加昂贵 “ 6”使用具有无锁技术的全局多线程池,并尝试通过使线程寻找新池(如果其使用的池为“已锁定”)来平衡可用池上的线程,以限制竞争。 (而不是等待),并让每个线程在线程局部变量中缓存最后使用的池。因此,线程是轻量级的,但是如果池的数量与活动线程的数量太少,则可能存在一些争用。     
一些想法: 当您有一个“ 14”时,添加元素并触发调整大小会使该容器中的引用/指针/迭代器无效,但不会直接访问指向对象的引用/指针。因此,间接层可能会解决您的问题,具体取决于您实际上在尝试使用这些引用/指针/迭代器。 在具有虚拟内存和大地址空间的系统中,您可以进行大量分配,而无需实际将页面从物理内存资源中分配,直到将其写入。因此,在这样的系统上,您最初可以为15英镑设置一个比以往任何时候都要大的容量,而不会觉得自己在浪费任何有价值的东西。 其他容器-
std::map<>
std::list<>
-在添加新元素时不会移动其现有元素,因此迭代器/指针/引用仍然有效。     

要回复问题请先登录注册