0%

linux memory fragmentation

Using SVID2/XPG interface to check heap memory.

before all: The GNU Allocator (The GNU C Library)

read this for a outline for gnu c malloc.

mallinfo

arena + hblkhd is the total size of malloced mem. More detailed, arena is the size of all heaps in all arenas, while hblkhd is the size of all mmapped regions.

fordblks is the key data for check memory fragmentation, this stands for size of all free chunks.

to check after a routine, if there got more allocated space, check arena + hblkhd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* malloc.h */
struct mallinfo
{
int arena; /* non-mmapped space allocated from system */
int ordblks; /* number of free chunks */
int smblks; /* number of fastbin blocks */
int hblks; /* number of mmapped regions */
int hblkhd; /* space in mmapped regions */
int usmblks; /* always 0, preserved for backwards compatibility */
int fsmblks; /* space available in freed fastbin blocks */
int uordblks; /* total allocated space */
int fordblks; /* total free space */
int keepcost; /* top-most, releasable (via malloc_trim) space */
};

Malloc Tunable Parameters

1
2
3
4
5
6
7
8
9
10
11
/* mallopt options that actually do something */
#define M_TRIM_THRESHOLD -1
#define M_TOP_PAD -2
#define M_MMAP_THRESHOLD -3
#define M_MMAP_MAX -4
#define M_CHECK_ACTION -5
#define M_PERTURB -6
#define M_ARENA_TEST -7
#define M_ARENA_MAX -8
/* General SVID/XPG interface to tunable parameters. */
extern int mallopt (int __param, int __val) __THROW;

Appendix

Reference

memory fragmentation

the most simple way is to limit the arena count

The M_AREANA_MAX,

This parameter sets the number of arenas to use regardless of the number of cores in the system.

The default value of this tunable is 0, meaning that the limit on the number of arenas is determined by the number of CPU cores online. For 32-bit systems the limit is twice the number of cores online and on 64-bit systems, it is eight times the number of cores online. Note that the default value is not derived from the default value of M_ARENA_TEST and is computed independently.

This parameter can also be set for the process at startup by setting the environment variable MALLOC_ARENA_MAX to the desired value.

If you known what you are doing, change ``M_MMAP_THRESHOLDshould also works. Since page size on x86_64 Linux are 4096(check from commands$getconf PAGESIZE` ), all value greater or equal to this would make sense.

Code to understand mallinfo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <malloc.h>

size_t heap_malloc_total, heap_free_total, mmap_total, mmap_count;

void print_info()
{
struct mallinfo mi = mallinfo();
printf("count by itself:\n");
printf("\theap_malloc_total=%lu heap_free_total=%lu heap_in_use=%lu\n\tmmap_total=%lu mmap_count=%lu\n",
heap_malloc_total * 1024, heap_free_total * 1024, heap_malloc_total * 1024 - heap_free_total * 1024,
mmap_total * 1024, mmap_count);
printf("count by mallinfo:\n");
printf("\theap_malloc_total=%lu heap_free_total=%lu heap_in_use=%lu\n\tmmap_total=%lu mmap_count=%u\n", mi.arena,
mi.fordblks, mi.uordblks, mi.hblkhd, mi.hblks);
printf("from malloc_stats:\n");
malloc_stats();
}

#define ARRAY_SIZE 200
int main(int argc, char **argv)
{
char *ptr_arr[ARRAY_SIZE];
int i;
for (i = 0; i < ARRAY_SIZE; i++)
{
ptr_arr[i] = (char *)malloc(i * 1024);
if (i < 128) // glibc默认128k以上使用mmap
{
heap_malloc_total += i;
}
else
{
mmap_total += i;
mmap_count++;
}
}
print_info();

for (i = 0; i < ARRAY_SIZE; i++)
{
if (i % 2 == 0)
continue;
free(ptr_arr[i]);

if (i < 128)
{
heap_free_total += i;
}
else
{
mmap_total -= i;
mmap_count--;
}
}

printf("\nafter free\n");
print_info();

return 1;
}