要避免频繁的调用malloc
和free
是为了优化程序的性能和效率。下面提供两种方法来减小malloc
和free
的开销:
1. 使用内存池
内存池是一种先分配好一定的内存存储池,在程序中使用的时候直接从池中获取内存,使用完后再归还给池中。它的优点在于如果内存池的容量足够,那么内存池中的内存可以重复使用,从而减小了malloc
和free
带来的开销。以下是使用内存池的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define BLOCK_SIZE 4096
typedef struct mem_block{
struct mem_block *next;
bool is_free;
}MEM_BLOCK;
typedef struct mem_pool{
MEM_BLOCK *free_list;
MEM_BLOCK *base_pool; // 内存池起始地址
size_t block_size;
size_t n_pool_blocks; // 内存池中总共有多少个内存块
}MEM_POOL;
MEM_POOL *mem_pool_create(size_t pool_size, size_t block_size) {
MEM_POOL *pool = malloc(sizeof(MEM_POOL));
if (pool) {
pool->free_list = NULL;
pool->block_size = block_size;
size_t n_blocks = pool_size / block_size;
pool->n_pool_blocks = n_blocks;
pool->base_pool = malloc(n_blocks * block_size);
MEM_BLOCK *last_block = NULL;
for (size_t i = 0; i < n_blocks; ++i) {
MEM_BLOCK *block = pool->base_pool + i * block_size;
block->is_free = true;
if (last_block) {
last_block->next = block;
} else {
pool->free_list = block;
}
last_block = block;
}
last_block->next = NULL;
}
return pool;
}
void *mem_pool_alloc(MEM_POOL *pool) {
if (!pool->free_list) return NULL;
MEM_BLOCK *block = pool->free_list;
pool->free_list = block->next;
block->is_free = false;
return block;
}
void mem_pool_free(MEM_POOL *pool, void *ptr) {
if (!ptr) return;
MEM_BLOCK *block = (MEM_BLOCK*)ptr;
block->is_free = true;
block->next = pool->free_list;
pool->free_list = block;
}
void mem_pool_destroy(MEM_POOL *pool) {
if (pool) {
if (pool->base_pool) free(pool->base_pool);
free(pool);
}
}
int main() {
MEM_POOL *pool = mem_pool_create(2 * BLOCK_SIZE, BLOCK_SIZE);
void *ptr1 = mem_pool_alloc(pool);
void *ptr2 = mem_pool_alloc(pool);
if (ptr1) printf("ptr1 has been allocated.\n");
if (ptr2) printf("ptr2 has been allocated.\n");
mem_pool_free(pool, ptr1);
mem_pool_free(pool, ptr2);
/* 建议:在程序结束时销毁内存池 */
mem_pool_destroy(pool);
return 0;
}
在此示例代码中,首先定义了一个内存块结构体MEM_BLOCK
,其中包含一个链表指针next
和一个布尔值is_free
。其次定义了一个内存池结构体MEM_POOL
,其中包含了一个内存块的链表指针free_list
,一个内存池的起始地址base_pool
,一个内存块的大小block_size
和内存池中总共有多少个内存块n_pool_blocks
。内存池的创建过程中,需要先分配好内存池的容量pool_size
,再根据内存块的大小block_size
计算出内存池中有多少个内存块,最后通过malloc
函数分配这些内存块:
pool->base_pool = malloc(n_blocks * block_size);
接着在循环中对内存块进行初始化,并将这些内存块按照链表的方式连接起来,同时将free_list
的指针指向链表的头节点,表示内存块都是未使用的:
for (size_t i = 0; i < n_blocks; ++i) {
MEM_BLOCK *block = pool->base_pool + i * block_size;
block->is_free = true;
if (last_block) {
last_block->next = block;
} else {
pool->free_list = block;
}
last_block = block;
}
内存池的分配过程中,只需要从free_list
中取出一个内存块即可。该内存块的状态需要更改为已使用,同时返回该内存块的指针:
void *mem_pool_alloc(MEM_POOL *pool) {
if (!pool->free_list) return NULL;
MEM_BLOCK *block = pool->free_list;
pool->free_list = block->next;
block->is_free = false;
return block;
}
内存池的释放过程中,需要将该内存块的状态更改为未使用,同时将该内存块挂到free_list
的链表头:
void mem_pool_free(MEM_POOL *pool, void *ptr) {
if (!ptr) return;
MEM_BLOCK *block = (MEM_BLOCK*)ptr;
block->is_free = true;
block->next = pool->free_list;
pool->free_list = block;
}
内存池的销毁过程中,需要将内存池中已经分配的内存释放掉,并将内存池的指针也释放:
void mem_pool_destroy(MEM_POOL *pool) {
if (pool) {
if (pool->base_pool) free(pool->base_pool);
free(pool);
}
}
2. 使用栈内存
栈内存通常在函数执行时分配,函数退出时自动释放。使用栈内存的一个优点在于分配和释放内存非常快,因为这些操作都只是在栈顶移动指针而已,并不需要进行内存的分配和释放。下面是使用栈内存的示例代码:
#include <stdio.h>
#define MAX_SIZE 100
typedef struct student {
int id;
char name[20];
double score;
}STUDENT;
int main() {
/*
* 可以使用该方式来动态计算数组元素的数量
* int n = sizeof(array) / sizeof(array[0]);
*/
STUDENT array[MAX_SIZE] = {
{1, "Alice", 99.5}, {2, "Bob", 86.5}, {3, "Mike", 90.0},
{4, "John", 77.0}, {5, "Lisa", 100.0}
};
int n = 5; // 数组元素的数量
double total_score = 0;
for (int i = 0; i < n; ++i) {
total_score += array[i].score;
}
double average_score = total_score / n;
printf("Average score: %5.2f\n", average_score);
return 0;
}
在此示例代码中,定义了一个结构体STUDENT
,并在main
函数中使用该结构体数组array
存储学生的信息。需要注意的是,在使用该数组之前需要确定数组元素的数量。在进行学生成绩统计时,仅需要对数组中的元素进行遍历即可。
需要注意的是,使用栈内存时需要注意栈空间的限制,不能存储过多的数据,否则会引发栈溢出等问题。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言避免malloc/free开销 - Python技术站