C ++:在循环中的固定内存块中分配

时间:2014-07-25 19:20:21

标签: c++ memory-management allocation placement

我有一个基本上是这样的应用程序:

Init();
while(true){
    read_data();
    process_data();
    write_processed_data();
}

一旦完成write_processed_data,循环段落中分配的数据就完全被丢弃了。更重要的是,每个循环段落中的分配数量都是以常数为界。

我以为我可以通过在可移动指针上使用新的贴图来分配   在一个固定大小的块内,然后在循环通道的末尾我只是 重置"可移动指针"到块的开头,从而完全避免删除。 然而,我的尝试并不是很成功,似乎比实现起来更难 最初计划。   这是一种常见的分配策略吗? 在这种程序中,我可以获得速度,而不必担心内存泄漏。

3 个答案:

答案 0 :(得分:2)

如果你有一个上限,你首先不需要堆。

这是最好的解决方案。

答案 1 :(得分:1)

感谢@EdHeal指出了以下方法背后的基本思路:

在你的循环之前,在你的内存块中“分配”你需要使用的所有具体数据类型的足够大的数组。将这些用作您的对象池集。与对象池的典型实现不同,您永远不必扩展池,因为在开始时创建阵列时,您可以知道可能使用的每种类型的对象数量的上限。 (您的问题陈述暗示您至少在进入循环之前就拥有此信息。)

在循环期间,每次需要新对象时,从其池中获取其指针。您可以实现一个函数,将指针放回池中以再次用作“新”对象,或者如果“新分配”的总数有一个已知限制,该数量不会比高水位大得多在任何时候使用的对象数量,您甚至不需要费心将对象放回池中。 (第二个选项会使池管理变得非常简单,因为您所要做的就是保持从每个池中获取的对象数量,并告诉您哪个对象是下一个“新”对象。)无论是哪种情况,在循环结束时,您重置池,以便所有对象都可以再次“新”。

我可能会创建一个名为Allocator的类来管理池,它可以为池中的每种对象提供一个函数,或者放回池中reset()函数在循环结束时调用。可能有更优雅的方式来完成这项工作。

请注意,如果您已经足够精确地知道所需对象数量的上限,那么您可以创建所有上述数据结构,而无需在堆上放置任何内容。

答案 2 :(得分:0)

避免大量不需要的新闻和删除的一种方法是使用对象池并覆盖类的新操作和删除操作符。基本上是:

// In header file
class Thing{...}

// In .cc file
namespace thingpool {
static std::vector<Thing*>* chunks = 0;
} 

void* Thing::operator new(size_t size){
  // If pool is not initialized
  if (!thingpool::chunks){
    thingpool::chunks = new std::vector<Thing*>;
    thingpool::chunks->reserve(100);  // or some upper bound on expected Things
  }

  void* memptr;
  if(!thingpool::chunks->empty()) {
    memptr = thingpool::chunks->back();
    thingpool::chunks->pop_back();
  } 
  else {
    memptr = ::malloc(size);
  }
  return memptr;
}

// put memory back in pool
void Thing::operator delete(void* ptr)
{
  if (thingpool::chunks)
    thingpool::chunks->push_back(static_cast<key*>(ptr));
}

并在某个时候清理东西池。