实现池内存API-处理联合

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现池内存API-处理联合相关的知识,希望对你有一定的参考价值。

我想为数据结构实现一个API,该API可以预先将内存分配给一定大小的多个对象,而不是每次都需要为每个对象使用'malloc'和'free'。

API应该包括以下三个功能:

pool* API_init(size_t sizeOfObj, int numOfObj)

接受两个参数,对象大小和我们希望存储的此类对象的数量,并返回指向池的指针-用来管理内存的数据结构。

void* API_malloc(Pool* pool)

接受池和用于单个对象新分配的返回指针。

void API_free(Pool* pool, void* obj)

接受两个参数,pool和需要标记为未使用的地址。

方法'API_malloc'和'API_free'的复杂度时间要求是恒定的,并且池的内存复杂度应该是'sizeOfObj'*'numOfObj'+常数。

为了处理碎片,我想将池定义为大小为'sizeOfObj'字节的块的链接列表,其中还包含指向下一个未使用块的指针。为了节省内存空间,我决定使用UNION定义块。

这是我的实现:

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

typedef struct Pool Pool;
typedef union Chunk Chunk;


union Chunk

    char* padding;
    Chunk* next;
;

struct Pool

    Chunk* nextFreeChunk;
;

Pool* API_init(int sizeOfObj, int numOfObj)

    Pool* res = (Pool*) malloc(sizeof(Pool));
    Chunk* next;
    Chunk* curr;

    for(int i = numOfObj -1; i >= 0; i--)

        curr = (Chunk*) malloc (sizeof(Chunk));
        curr->padding = (char*) malloc(sizeOfObj);

        if(i < numOfObj -1)
            curr->next = next;

        next = curr;
    

    res->nextFreeChunk = curr;
    return res;


void* API_malloc(Pool* pool)

    void* res = pool->nextFreeChunk;
    pool->nextFreeChunk = (pool->nextFreeChunk)->next;
    return res;


void API_free(Pool* pool, void* obj)

    Chunk* ch = (Chunk*) obj;
    ch->next = pool->nextFreeChunk;
    pool->nextFreeChunk = ch;

我的问题是,按照我的定义,这些块不一定具有给定的'sizeOfObj'大小,并且char指针浪费了内存(更多的是常量)。

[我知道union不能拥有一个灵活的char数组作为成员,因此我无法在'API_init'中定义成员'char padding [sizeOfObj]'。

非常感谢您提出的解决我的问题或提出新实施方法的建议。

答案

[您有一个问题,因为paddingnext共享相同的内存(属于一个并集),所以当您分配给next时,padding指向的任何数据都将丢失。

您的解决方案是让您的块成为是您的数据,或成为下一个空闲块的指针。因此,对于每个malloc(),我们需要分配max(sizeof(union Chunk), sizeOfObj)

union Chunk
    char data[1]; /* `1` is a dummy value, the compiler doesn't actually really care 
                     if we allocate and use more than 1 char */ 
    union Chunk* next;
;


/* We return `struct Pool` by value to save a `malloc()`  (c is not java)*/ 
struct Pool API_init(size_t sizeOfObj, size_t numOfObj)

    union Chunk* prev = NULL;
    size_t chunksize = max(sizeof (union Chunk), sizeOfObj);

    /* counting upwards is easier than downwards */
    for(size_t i = 0; i < numOfObj; i++)

        /* We don't cast the return value from `malloc()`. This is c, not c++ */
        curr = malloc(chunksize);

        curr->next = prev;

        prev = curr;
    

    struct Pool res;   
    res.nextFreeChunk = curr;
    return res;

您的API_malloc()API_free()看起来不错,除了它们是用c ++而不是c编写的。用c编写时不要使用c ++语法。并使用c编译器,而不是c ++编译器。

您可以通过一次分配整个池而不是使用多个malloc()来改善这一点:

struct Pool
    char *buffer;
    Chunk* nextFreeChunk;
;

struct Pool API_init(size_t sizeOfObj, size_t numOfObj)

    size_t chunksize = max(sizeof (union Chunk), sizeOfObj);

    /* Checking for overflow is left as an exercise for the reader */
    size_t buffersize = numOfObj * chunksize;

    char *buffer = malloc(buffersize);


    for(size_t i = 0; i < numOfObj - 1; i++)

        union Chunk *curr = (union Chunk *)(buffer + i * chunksize);
        curr->next = (union Chunk *)(buffer + (i+1) * chunksize);

    

    if (numOfObj)
    
        union Chunk *last = (union Chunk *)(buffer + (numOfObj - 1) * chunksize);
        last->next = NULL;
    


    struct Pool res;
    res.buffer = buffer;    
    res.nextFreeChunk = (union Chunk *)buffer;
    return res;

为简洁起见,自然不会进行任何错误检查和小错误修正

以上是关于实现池内存API-处理联合的主要内容,如果未能解决你的问题,请参考以下文章

Java线程池内存模型与参数

code3728 联合权值

sql SGA池内存的详细信息

Unity池内存,碎片

如何创建作为多个查询联合的 Django 模型字段,以实现覆盖字段?

图像处理中必用到的公式——联合因素评价指标定义与C/C++实现