C语言避免malloc/free开销

重复分配然后释放结构体会产生一些开销,可能导致巨大的性能瓶颈。解决这个问题的一种办法是为分配的结构体单独维护一个表。当用户不再需要某个结构体实例时,将其返回结构体池中。当我们需要某个实例时,从结构体池中获取一个对象。如果池中没有可用的元素,我们就动态分配一个实例。这种方法高效地维护一个结构体池,能按需使用和重复使用内存。

为了说明这种方法,我们会用之前定义的Person结构体。用数组维护结构体池,也可以用链表等更复杂的表,6.4.1节有相关说明。为了让示例简单,我们用了指针数组,声明如下:

#define LIST_SIZE 10
Person *list[LIST_SIZE];

使用表之前需要先初始化。下面的函数为数组每个元素赋值NULL

void initializeList() {
    for(int i=0; i<LIST_SIZE; i++) {
        list[i] = NULL;
    }
}

我们用两个函数来添加和获取结构体。第一个是getPerson函数,如下所示。如果存在可用的结构体,这个函数从表中获取一个。将数组的元素跟NULL比较,返回第一个非空的元素,然后将它在list中的位置赋值为NULL。如果没有可用的结构体,那就创建并返回一个新的Person实例。这样就避免了每次需要结构体时都动态分配内存的开销,我们只在池中为空时才分配内存。返回实例的初始化可以在返回之前就做好,也可以由调用者来做,取决于应用程序的需要。

Person *getPerson() {
    for(int i=0; i<LIST_SIZE; i++) {
        if(list[i] != NULL) {
            Person *ptr = list[i];
            list[i] = NULL;
            return ptr;
        }
    }
    Person *person = (Person*)malloc(sizeof(Person));
    return person;
}

第二个函数是returnPerson,这个函数要么将结构体返回表,要么把结构体释放掉。我们会检查数组元素看看有没有NULL值,有的话就将person添加到那个位置,然后返回指针。如果表满了,就用deallocatePerson函数释放person内的指针,然后释放person,最后返回NULL

Person *returnPerson(Person *person) {
    for(int i=0; i<LIST_SIZE; i++) {
        if(list[i] == NULL) {
            list[i] = person;
            return person;
        }
    }
    deallocatePerson(person);
    free(person);
    return NULL;
}

下面的代码说明了表的初始化,以及如何将一个结构体添加到表中:

initializeList();
Person *ptrPerson;

ptrPerson = getPerson();
initializePerson(ptrPerson,"Ralph","Fitsgerald","Mr.",35);
displayPerson(*ptrPerson);
returnPerson(ptrPerson);

这种方法有个问题,就是表的长度。如果表太短,那么就需要更频繁地分配并释放内存。如果表太长而没有使用结构体,那么就会浪费大量的内存,也不能用在其他地方。可以用更复杂的表管理策略来管理表的长度。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程