C 自由函数(不使用 malloc)

标签 c memory-management struct linked-list free

我正在编写自己的内存分配程序(不使用 malloc),现在我只能使用 free 函数(在我的代码中为 free)。我相信分配的功能就在那里,唯一的问题在于免费功能。因此,通过运行下面的代码,我可以分配 32 个 block :每个 block 的大小为 48 + 16( header 大小)。 那么如何在分配它们之后立即释放/释放它们呢?你能看看我的免费功能并指出正确的方向吗?

P.S.:这是为了学习目的。我试图了解结构、链表、内存分配。 提前致谢。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BUFFER_SIZE 2048

typedef struct blk_struct
{
    size_t  size_blk;
    struct  blk_struct *next;
    char    data[0];
}blk_struct;

struct blk_struct *first = NULL;
static char buffer[BUFFER_SIZE];

void *asalloc(size_t size)
{
    int nunits = (size + sizeof(blk_struct));
    static int val = 1;

    blk_struct *block, *current;

    //locate position for block
    if(first == NULL)
    {
        block = (blk_struct *)&buffer[0];

        // Sanity check size.
        if(nunits > BUFFER_SIZE)
            return NULL;

        // Initialise structure contents.
        block->size_blk = size;
        block->next     = NULL;

        // Add to linked list.
        first = block;

        // Give user their pointer.
        return block->data;
    }
    //create a free list and search for a free block
    for(current = first; current != NULL; current = current->next)
    {
        // If this element is the last element.
        if(current->next == NULL)
        {
            block = (blk_struct *) (current->data + current->size_blk);

            // Check we have space left to do this allocation
             if((blk_struct *) &block->data[size] >
                     (blk_struct *) &buffer[BUFFER_SIZE])
             {
                 printf("No more space\n");
                 return NULL;
             }

            // Initialise structure contents.
            block->size_blk = size;
            block->next     = NULL;

            // Add to linked list.
            current->next   = block;
            // Give user their pointer.
            return block->data;
        }
    }
    printf("List Error\n");
    return NULL;
}

// 'Free' function. blk_ptr = pointer to the block of memory to be released
void asfree(void *blk_ptr)
{
    struct blk_struct *ptr = first;
    struct blk_struct *tmp = NULL;

    while(ptr != NULL)
    {
        if(ptr == blk_ptr)
        {
            printf("Found your block\n");
            free(blk_ptr);
            break;
        }
        tmp = ptr;
        ptr = ptr->next;
    }
}

// Requests fixed size pointers
int test_asalloc(void)
{
    void *ptr = NULL;
    int size = 48;
    int i = 1;
    int total = 0;

    do
    {
        ptr = asalloc(size);

        if(ptr != NULL)
        {
            memset(ptr, 0xff, size);
            printf("Pointer %d = %p%s", i, ptr, (i % 4 != 0) ? ", " : "\n");
            // each header needs 16 bytes: (sizeof(blk_struct))
            total += (size + sizeof(blk_struct));
            i++;
        }
        asfree(ptr); // *** <--- Calls the 'free' function ***
    }
    while(ptr != NULL);
    printf("%d expected %zu\nTotal size: %d\n", i - 1,
            BUFFER_SIZE / (size + sizeof(blk_struct)), total);
}

int main(void)
{
    test_asalloc();
    return 0;
}

最佳答案

我可以看出您的 asfree 存在一些问题。

寻找区 block 头时需要减去sizeof(blk_struct)。由于用户想要释放的已分配数据就在 header 后面,您有指向该数据的指针,而不是 header 。

第二个问题是拿到header之后怎么办。您不能只调用免费数据。您需要在标题中有一些标志并将该 block 标记为空闲。下次你尝试分配一个 block 时,你需要能够重用空闲 block ,而不仅仅是在最后创建新 block 。能够将一个大的空闲 block 分成两个较小的 block 也很好。为避免碎片,需要将相邻的空闲 block 合并为一个更大的 block 。

目前我正在编写一个操作系统作为一个学校项目。我建议您使用像这样工作的简单分配器:

  • 内存块的标题包含指向相邻 block 的链接和空闲标志。
  • 一开始有一个大块,上面有空闲标志,覆盖了整个内存。
  • 当调用 malloc 时,从头到尾搜索 block 。当找到足够大的 block 时,它会被分成两部分(分配一个和免费提醒)。返回指向已分配 block 数据的指针。
  • 当调用 free 时,匹配 block 被标记为空闲。如果相邻 block 也空闲,则将它们合并。

我认为这是能够在不产生碎片和丢失内存的情况下执行 malloc 和 free 的基础。

页眉和页脚的结构如下所示:

// Header of a heap block
typedef struct {
    // Size of the block including header and footer
    size_t size;

    // Indication of a free block
    bool free;

    // A magic value to detect overwrite of heap header.
    uint32_t magic;

} heap_block_head_t;


// Footer of a heap block
typedef struct {
    // A magic value to detect overwrite of heap footer.
    uint32_t magic;

    // Size of the block
    size_t size;

} heap_block_foot_t;

像上面这样的堆满了带有页眉和页脚的 block 的堆很像一个链表。 block 不会明确地描述它们的邻居,但只要你现在它们在那里,你就可以很容易地找到它们。如果您有一个标题的位置,那么您可以将 block 大小添加到该位置,并且您有下一个 block 的标题位置。

// Get next block
heap_block_head_t *current = ....
heap_block_head_t *next = (heap_block_head_t*)(((void*) current) + current->size);

// Get previous block
heap_block_head_t *current = ....
heap_block_foot_t *prev_foot = (heap_block_foot_t*)(((void*) current) - sizeof(heap_block_foot_t));
heap_block_head_t *prev = (heap_block_head_t*)(((void*) prev_foot) + sizeof(heap_block_foot_t) - prev_foot->size);

// Not sure if this is correct. I just wanted to illustrate the idea behind.
// Some extra check for heap start and end are needed

希望这对您有所帮助。

关于C 自由函数(不使用 malloc),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13709829/

相关文章:

c++ - 结构体中的友元函数有什么用?

c - 如何使用 gcc 4.8.4 [-Wunused-parameter] 摆脱 C 中的未使用参数警告

c - 使用用户定义的函数用随机数/错误填充数组

mysql - CentOS 内存使用情况。已使用约 22GB RAM(22GB 可用内存)

c++ - 与 Valgrind 一起运行时,malloc 返回 null

c++ - 为什么我得到 "Invalid Allocation Size: 4294967295 Bytes"而不是 std::bad_alloc 异常?

c - 我如何在 CFFI 中包装包含结构指针的结构?

c - 需要有关伪代码/算法的帮助 - 链表合并

c - 将字符串拆分为结构体的元素

c - C中的结构被视为指针