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

Issue accessing free list nodes by memory address in pool allocator

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

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

Class 描述:

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 etc)

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

你也必须修复这条线

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