c++ - 通过池分配器中的内存地址访问空闲列表节点

标签 c++ memory-management allocation

我正在尝试编写一个简单的池分配器,用于在 C++ 中进行分配和释放,作为大学类(class)任务的一部分。我们得到了对 git-user floooh 的 oryol 引擎的引用,https://github.com/floooh/oryol/blob/master/code/Modules/Core/Memory/poolAllocator.h ,因此我尝试通过将池拆分为需要时分配的水坑来做类似的事情。从一个开始,然后随着内存需求的增加而递增。

在我的案例中,每个水坑都维护着自己的空闲节点列表,而我在创建第一个水坑时已经失败了:当我尝试访问节点结构数据成员时出现段错误。下面是我的池分配器类描述以及用于添加水坑的构造函数和函数。我在 allocNewPuddle() 失败的地方评论了大写锁定“SEGMENTATION FAULT”,该函数的第 10 行。

类说明:

template<class T> class memAllocator {
public:
  memAllocator();
  ~memAllocator();

  struct Puddle;

  struct mNode {
    mNode* nextN;
    mNode* prevN;
    uint puddle;
  };

  struct Puddle {
    mNode* headN_free;
    mNode* headN_occ;
  };

  uint numPuddles;
  static const uint nodesInPuddle = 512;
  static const uint maxPuddles = 512;
  Puddle* puddles[maxPuddles];

  uint nodeSize;
  uint elemSize;
  uint puddleStructSize;

  void allocNewPuddle();
  void* allocate();
  void deallocate(void* obj);
  void* findNextFreeNode();
  template<typename... ARGS> T* create(ARGS&&... args);
  void destroy(T* obj);

};

构造函数:

template<class T>
memAllocator<T>::memAllocator() // creates instance of allocator starting with one puddle allocated
{
  this->numPuddles = 0;
  this->nodeSize = sizeof(mNode);
  this->elemSize = nodeSize + sizeof(T);
  this->puddleStructSize = sizeof(Puddle);

  allocNewPuddle();
}

添加一个新的水坑:

template<class T>
void memAllocator<T>::allocNewPuddle() // allocates a new puddle
{
  // allocate memory for one puddle
  assert(numPuddles < maxPuddles);
  Puddle* newPuddle = (Puddle*) malloc(puddleStructSize + nodesInPuddle * elemSize);

  // allocate nodes in free list pointed to by puddle struct
  newPuddle->headN_free = (mNode*) (newPuddle + puddleStructSize + (nodesInPuddle-1)*elemSize);
  for (int i = nodesInPuddle-2; i >= 0; i--) {
    mNode* curNode = (mNode*) (newPuddle + puddleStructSize + i*elemSize);
    // Fails here when attempting to access mNode struct members
    curNode->puddle = numPuddles; // SEGMENTATION FAULT HERE ON FIRST ITERATION
    curNode->prevN = nullptr;
    curNode->nextN = newPuddle->headN_free;
    curNode->nextN->prevN = curNode;
    newPuddle->headN_free = curNode;
  }
  newPuddle->headN_occ = nullptr;
  puddles[numPuddles] = newPuddle;
  numPuddles++;
}

这是我的 main.cc:

#include "memAllocator.h"
#include <iostream>

class Test {
public:
  Test();
  ~Test();
  int arr[5];
};

Test::Test() {
  for (int i = 0; i < 5; i++) {
     this->arr[i] = i;
  }
}

Test::~Test() {
  std::cout << "destructor called" << std::endl;
}

int main(int argc, char* argv[]) {
  memAllocator<Test> memPool = memAllocator<Test> ();
  Test* test = memPool.create();
  for (int i = 0; i < 5; i++) {
    std::cout << test->arr[i] << std::endl;
  }
  memPool.destroy(test);
  for (int i = 0; i < 5; i++) {
    std::cout << test->arr[i] << std::endl;
  }
}

我的猜测是我正在用 C++ 指针做一些非常天真的事情,但据我所知,上面的方法应该可行。如果没有,那么我期待着好好的责骂。

哦,正如你所看到的,我没有费心去对齐内存,因为它是一个小任务,据我所知,这对于它的工作来说并不是必需的,它只会让它更快,但这是否可能导致在需要更多内存时读取和写入错误的内存?

最佳答案

你的地址计算不正确

mNode* curNode = (mNode*) (newPuddle + puddleStructSize + i*elemSize);

newPuddle 是 Puddle 指针,但您尝试添加字节。因此,您的新地址远远超出了已分配内存缓冲区的末尾。因此,您必须将显式转换添加到字节指针(char、uint8_t 等)

mNode* curNode = (mNode*) ((char*)newPuddle + puddleStructSize + i*elemSize);

你也必须修复这条线

newPuddle->headN_free = (mNode*) (newPuddle + puddleStructSize + (nodesInPuddle-1)*elemSize);

关于c++ - 通过池分配器中的内存地址访问空闲列表节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33734088/

相关文章:

c# - 如何在 Visual Studio 2008 中创建用于 C# 应用程序的 .dll?

c++ - 如何使 C++ 编译器接受 2_147_483.78 作为有效的 float

iOS 应用程序在内存不足的情况下的行为

c++ - 了解 C++ 动态分配

c++:子进程输出到stdin

c++ - boostscoped_lock 消耗太多CPU

c++ - 使用 marmalade SDK 的内存使用问题

Java非阻塞内存分配

c - 具有不同长度数组成员的结构数组 C

c - 理解来自 K&R 的代码