简体   繁体   English

如何实现 memory 分配器

[英]how to implement a memory allocator

I'm trying to implement the freelist algorithm to allocate memory.我正在尝试实现freelist算法来分配memory。 The two functions I'm trying to write can be described as shown below.我正在尝试编写的两个函数可以描述如下。

// allocates a block of memory of at least size words and returns the address of that memory or 0 if no memory could be allocated.
int64_t *mymalloc(int64_t size)

// deallocates the memory stored at addr. the address will either be one allocated by mymalloc or the value 0.
void myfree(int64_t *addr)

The implementations of these functions should only use memory returned by the function pool(), whose signature is described below.这些函数的实现只能使用 function pool() 返回的 memory,其签名如下所述。 Thus it cannot use the functions new, delete, malloc, calloc, realloc, etc.因此它不能使用函数 new、delete、malloc、calloc、realloc 等。

// pool is a function that returns the address of a beginning // of a block of RAM that may be used for dynamic memory 
// allocation. The size of the pool in bytes is stored in the // first word, which can be assumed to be a multiple of 8. 
// When pool() is called, the first word isn't always overwritten with its size.
// Each word is an int64_t *, and so is 8 bytes.
// Assume this function works.
int64_t *pool();

I think defining some global variables like freelst, which points to the start of the freelst, may be helpful.我认为定义一些全局变量,例如指向 freelst 开始的 freelst,可能会有所帮助。 It can be defined as它可以定义为

int64_t *freelst = pool();

I know that when allocating memory, there are some steps to follow:我知道在分配memory时,有一些步骤要遵循:

  • The free list pointer should be updated accordingly.空闲列表指针应相应更新。
  • The number of allocated blocks should be incremented.分配块的数量应该增加。
  • The amount of memory allocated should be subtracted from the first word of the freelist, so that the first word always stores the size of memory available.分配的 memory 的数量应该从 freelist 的第一个字中减去,这样第一个字总是存储 memory 可用的大小。
  • One needs to check if the current block of memory has been previously freed.需要检查 memory 的当前块是否先前已被释放。

When deallocating memory, one needs to ensure addresses are inserted into the freelist in increasing order so that neighbours can be determined.在释放 memory 时,需要确保地址按递增顺序插入空闲列表,以便确定邻居。 If neighbours (which differ by 8) are free, they need to be merged, and as many times as necessary until no free neighbours are encountered to reduce fragmentation.如果邻居(相差 8)是空闲的,则需要合并它们,并根据需要合并多次,直到没有遇到空闲邻居以减少碎片。 Also, the second word of the freelst should be a pointer to the next word of the free另外,freelst 的第二个字应该是指向 freelst 下一个字的指针

Below is some code I've come up with for this problem.下面是我为这个问题提出的一些代码。 It's incomplete, but the basic ideas are there.它不完整,但基本的想法就在那里。

#include <iostream>
#include <cstdint>
#include "pool.h" // place where pool is defined


const int NODE_SIZE = 8;

int64_t *freelst = pool();

int64_t *start_of_pool = freelst; // just keep this fixed I guess

// assume that the pool function works.

int64_t *mymalloc(int64_t size) {
  
  int64_t *currentBlock = freelst;
  while (currentBlock) {
    if (*currentBlock >= size) { // if the currentBlock is large enough, set it to this value (we're doing first fit).
       break;
    }
    currentBlock = currentBlock + 1; // since incrementing involves moving to the address that's one word past the current one.
  }
  // assuming we've found a large enough block, we now have to allocate it
  if (currentBlock == 0) {
    return 0; // I think this should occur because not enough memory was found
  }
  int64_t *prev_val = freelst; // save the previous value of the freelist
  freelst = freelst + 1 + *currentBlock; // assuming *currentBlock is the size of currentBlock.
  *freelst -= NODE_SIZE + *currentBlock; // update the size of the freelst here (though likely this was done incorrectly)
  return currentBlock + 1; // return address one word after currentBlock
  // is this all if we're trying to implement a linked list using raw pointers?
  // I don't think so, but I'm not sure what else to add.
}

void myfree(int64_t *p) {
    if (p == 0) { 
        return; // of course if we're freeing a nullptr, we should return 0.
    }
    // assume the freelst is already in ascending order of course.
    // sort the freelst in linear time by positioning the currentBlock into the right place.
    // the basic idea is to use insertion sort.
    // find where the address p is in the free list.
    // I think another method would be to update the prevBlock as the currentBlock is being updated.
    int64_t *currentBlock = freelst; 
    int64_t *prevBlock = freelst;
    while (currentBlock != 0 && currentBlock + 1 <= p) { // comparing addresses
        prevBlock = currentBlock; // so it's set to the previous block
        currentBlock = (int64_t *)*(currentBlock + 1); // set it to the next address
        // as a linked list, I'm thinking of doing something like:
        // prevBlock = currentBlock;
        // currentBlock = currentBlock->next;
    }
    // after exiting, either currentBlock = 0, in which case p is the largest address,
    // or currentBlock + 1 > p, so it's smaller than the current address.
    if (currentBlock == 0) { // then p is the largest address
        if ((int64_t *)*(prevBlock + 1) != currentBlock) throw std::invalid_argument("A likely error occurred as prevBlock + 1 != currentBlock.");
        *(prevBlock + 1) = (int64_t)p;
        *(p + 1) = 0;
        // p->next = 0
        // prevBlock->next = p;

    } else {
        if (prevBlock == currentBlock) { // in this case currentBlock was the start of the freelst
            int64_t *temp = (int64_t *)*(currentBlock + 1);
            *(prevBlock + 1) = (int64_t)p; // cast so it passes type-checking
            *(p + 1) = (int64_t)temp;
            // here I'm trying to mimic what's done for a linked list:
            // int64_t *temp = currentBlock->next;
            // prevBlock->next = p;
            // p->next = temp; 
        } else {
            *(prevBlock + 1) = (int64_t)p;
            *(p + 1) = (int64_t)currentBlock;
            // here's what I think might be the equivalent for a linked list:
            
            // prevBlock->next = p;
            // p->next = currentBlock;
        }
    }
    if (currentBlock != 0) { // if it not null
        if (currentBlock + 1 + *currentBlock == (int64_t *)(currentBlock + 1)) { // check if currentBlock is adjacent to prevBlock
            *currentBlock += *(int64_t *)*(currentBlock + 1) + NODE_SIZE;
        }
        // link current block to next next block
        *(currentBlock + 1) = (int64_t)((int64_t *)*(currentBlock + 1) + 1);
    }
    // assuming sorting was done correctly, check if addresses are adjacent
    if (prevBlock + 1 + *prevBlock == currentBlock) { // if you add one word plus the size of the previous block to get the
        // currentBlock
        if (currentBlock == 0) throw std::invalid_argument("A likely error occurred. currentBlock was 0 even though it should have been defined.");
        *prevBlock += *currentBlock + NODE_SIZE; // add the sizes of both the currentBlock and previous block,
        // assuming they aren't null of course.
        // so currentBlock->next->size + NODE_SIZE;
        // link previous block to next block
        *(prevBlock + 1) = (int64_t)(currentBlock + 1);

    }

}

Any help as to how to implement these functions/cases to consider that I've missed with code that deals with them would be appreciated.任何有关如何实现这些功能/案例的帮助,以考虑到我错过了处理它们的代码,我们将不胜感激。 I can also clarify things if necessary.如有必要,我也可以澄清一些事情。

I tried looking at this website for some help too, but I'm still having issues.我也尝试查看此网站寻求帮助,但我仍然遇到问题。

how to implement a memory allocator如何实现 memory 分配器

At high level, there are essentially two ways to acquire memory for a custom allocator:在高层次上,基本上有两种方法可以为自定义分配器获取 memory:

  • Allocate memory using an implementation defined way.使用实现定义的方式分配 memory。 The exact details depend on the target system, so first step is to find out what system you are targeting.确切的细节取决于目标系统,所以第一步是找出你的目标系统。
  • Or allocate memory using a standard way (standard allocator, new, malloc, static storage, ...)或使用标准方式分配 memory(标准分配器,新的,malloc,static 存储,...)

Once you've acquired the memory, you need some data structure to keep track of memory that has been allocated through the allocator.获得 memory 后,您需要一些数据结构来跟踪已通过分配器分配的 memory。 You seem to have roughly described the "free list" structure, which is commonly used for this purpose.您似乎已经大致描述了通常用于此目的的“空闲列表”结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM