При использовании malloc или strdup вам необходимо дополнительно 16 байтов для управления.
Когда вы выделяете много малой памяти, это дополнительное пространство также занимает много памяти.
Итак, рассмотрим собственную управляющую память или tcmalloc, jemalloc
Ниже приведены данные теста:
gcc -otest test.c -Wall -O3 -g
[test_strdup] cost time: 1085247 us, use memory: 839.81 MB
[test_optimized] cost time: 394635 us, use memory: 411.71 MB
gcc -otest test.c -Wall -O3 -g -ltcmalloc
[test_strdup] cost time: 627160 us, use memory: 461.07 MB
[test_optimized] cost time: 397938 us, use memory: 422.85 MB
gcc -otest test.c -Wall -O3 -g -ljemalloc
[test_strdup] cost time: 749875 us, use memory: 481.77 MB
[test_optimized] cost time: 330825 us, use memory: 451.96 MB
Ниже приведен тестовый код
Просто для сравнения распределения памяти в тестовом коде есть утечка памяти.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/sysinfo.h>
#define ROWS 35
#define COLS (1000*10000/ROWS)
#define MB (1024*1024)
#define TEST_STR "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
struct node {
char *value;
};
long current_time()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000L + tv.tv_usec;
}
long current_usemem()
{
FILE *fp;
long resident = 0;
fp = fopen("/proc/self/statm", "r");
if (fp) {
if (fscanf(fp, "%*s %ld ", &resident) != 1)
resident = 0;
fclose(fp);
}
resident *= 4096;
return resident;
}
void test_strdup()
{
char temp[500];
struct node **arrayofnodes[ROWS];
int i, j;
long start_time, end_time;
long start_usemem, end_usemem;
strcpy(temp, TEST_STR);
start_usemem = current_usemem();
start_time = current_time();
for(i = 0; i < ROWS; i++) {
arrayofnodes[i] = (struct node **)malloc(COLS * sizeof(struct node *));
for(j = 0; j < COLS; j++) {
arrayofnodes[i][j] = (struct node *)malloc(sizeof (struct node));
}
}
for(i = 0; i < ROWS; i++) {
for(j = 0; j < COLS; j++) {
arrayofnodes[i][j]->value = strdup(temp);
}
}
end_time = current_time();
end_usemem = current_usemem();
printf("[%s] cost time: %ld us, use memory: %.2f MB\n",
__FUNCTION__, end_time - start_time,
(end_usemem - start_usemem) / 1024.0 / 1024);
}
struct memory_chunk {
struct memory_chunk *next;
char *cur;
char *end;
char buf[0];
};
struct memory_pool {
struct memory_chunk *head;
};
void *pool_alloc(struct memory_pool *pool, size_t size)
{
void *ret;
struct memory_chunk *chunk;
chunk = pool->head;
if (chunk == NULL || chunk->cur + size >= chunk->end) {
size_t len = (size < MB ? MB : size + sizeof(*chunk));
chunk = (struct memory_chunk *)malloc(len);
chunk->next = pool->head;
chunk->end = (char *)chunk + len;
chunk->cur = chunk->buf;
pool->head = chunk;
}
ret = chunk->cur;
chunk->cur += size;
return ret;
}
char *pool_strdup(struct memory_pool *pool, const char *s)
{
size_t size = strlen(s) + 1;
void *ret = pool_alloc(pool, size);
memcpy(ret, s, size);
return ret;
}
void test_optimized()
{
char temp[500];
struct node ***arrayofnodes;
int i, j;
long start_time, end_time;
long start_usemem, end_usemem;
struct memory_pool pool = {NULL};
strcpy(temp, TEST_STR);
start_usemem = current_usemem();
start_time = current_time();
arrayofnodes = (struct node ** *)pool_alloc(&pool, ROWS * sizeof(struct node **));
for(i = 0; i < ROWS; i++) {
arrayofnodes[i] = (struct node **)pool_alloc(&pool, COLS * sizeof(struct node *));
for(j = 0; j < COLS; j++) {
arrayofnodes[i][j] = (struct node *)pool_alloc(&pool, sizeof(struct node));
}
}
for(i = 0; i < ROWS; i++) {
for(j = 0; j < COLS; j++) {
arrayofnodes[i][j]->value = pool_strdup(&pool, temp);
}
}
end_time = current_time();
end_usemem = current_usemem();
printf("[%s] cost time: %ld us, use memory: %.2f MB\n",
__FUNCTION__, end_time - start_time,
(end_usemem - start_usemem) / 1024.0 / 1024);
}
int main()
{
test_strdup();
test_optimized();
return 0;
}