第九章:内存管理

第九章:内存管理

9.1 内存管理的基本概念

内存管理的目标

内存管理的主要目标:

  1. 内存分配
  2. 内存回收
  3. 内存保护
  4. 内存共享

示例代码:

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

int main() {
// 内存分配
int *ptr = malloc(sizeof(int));
if (!ptr) {
perror("malloc");
return 1;
}

// 内存使用
*ptr = 42;
printf("Value: %d\n", *ptr);

// 内存回收
free(ptr);

// 内存映射
void *mapped = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mapped == MAP_FAILED) {
perror("mmap");
return 1;
}

// 使用映射内存
int *mapped_ptr = mapped;
*mapped_ptr = 100;
printf("Mapped value: %d\n", *mapped_ptr);

// 解除映射
munmap(mapped, 4096);

return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc memory_basic.c -o memory_basic

# 运行
./memory_basic

内存分配算法

常见的内存分配算法:

  1. 首次适应
  2. 最佳适应
  3. 最差适应
  4. 循环首次适应

示例代码:

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
#include <stdio.h>
#include <stdlib.h>

// 内存块结构
typedef struct block {
size_t size;
struct block *next;
int free;
} block_t;

// 内存分配函数
void *my_malloc(size_t size) {
// 实现首次适应算法
block_t *current = heap_start;
while (current) {
if (current->free && current->size >= size) {
// 分配内存
current->free = 0;
return (void *)(current + 1);
}
current = current->next;
}
return NULL;
}

// 内存释放函数
void my_free(void *ptr) {
if (!ptr) return;

block_t *block = (block_t *)ptr - 1;
block->free = 1;

// 合并相邻的空闲块
block_t *current = heap_start;
while (current) {
if (current->free && current->next && current->next->free) {
current->size += current->next->size;
current->next = current->next->next;
}
current = current->next;
}
}

9.2 内存管理的实现

页式管理

页式管理的特点:

  1. 固定大小的页
  2. 页表映射
  3. 虚拟地址转换

示例代码:

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

#define PAGE_SIZE 4096

int main() {
// 分配一页内存
void *page = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (page == MAP_FAILED) {
perror("mmap");
return 1;
}

// 使用页面
int *ptr = page;
*ptr = 42;
printf("Page value: %d\n", *ptr);

// 修改页面权限
if (mprotect(page, PAGE_SIZE, PROT_READ) == -1) {
perror("mprotect");
return 1;
}

// 解除映射
munmap(page, PAGE_SIZE);

return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc page_manage.c -o page_manage

# 运行
./page_manage

段式管理

段式管理的特点:

  1. 变长段
  2. 段表映射
  3. 段保护

示例代码:

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

int main() {
// 分配代码段
void *code_seg = mmap(NULL, 4096, PROT_READ | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (code_seg == MAP_FAILED) {
perror("mmap code");
return 1;
}

// 分配数据段
void *data_seg = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (data_seg == MAP_FAILED) {
perror("mmap data");
return 1;
}

// 使用数据段
int *data = data_seg;
*data = 100;
printf("Data value: %d\n", *data);

// 解除映射
munmap(code_seg, 4096);
munmap(data_seg, 4096);

return 0;
}

编译和运行命令:

1
2
3
4
5
# 编译
gcc segment_manage.c -o segment_manage

# 运行
./segment_manage

9.3 内存管理的优化

内存池

内存池的实现:

  1. 预分配内存
  2. 快速分配
  3. 减少碎片

示例代码:

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define POOL_SIZE 1024
#define BLOCK_SIZE 32

typedef struct memory_pool {
char *memory;
size_t used;
struct memory_pool *next;
} memory_pool_t;

// 创建内存池
memory_pool_t *create_pool() {
memory_pool_t *pool = malloc(sizeof(memory_pool_t));
if (!pool) return NULL;

pool->memory = malloc(POOL_SIZE);
if (!pool->memory) {
free(pool);
return NULL;
}

pool->used = 0;
pool->next = NULL;
return pool;
}

// 从内存池分配
void *pool_alloc(memory_pool_t *pool, size_t size) {
if (size > BLOCK_SIZE) return NULL;

if (pool->used + size > POOL_SIZE) {
// 创建新的内存池
memory_pool_t *new_pool = create_pool();
if (!new_pool) return NULL;

new_pool->next = pool;
pool = new_pool;
}

void *ptr = pool->memory + pool->used;
pool->used += size;
return ptr;
}

// 释放内存池
void free_pool(memory_pool_t *pool) {
while (pool) {
memory_pool_t *next = pool->next;
free(pool->memory);
free(pool);
pool = next;
}
}

内存对齐

内存对齐的实现:

  1. 计算对齐大小
  2. 调整分配大小
  3. 对齐地址

示例代码:

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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

// 计算对齐后的地址
void *align_ptr(void *ptr, size_t alignment) {
uintptr_t addr = (uintptr_t)ptr;
uintptr_t aligned = (addr + alignment - 1) & ~(alignment - 1);
return (void *)aligned;
}

// 分配对齐的内存
void *aligned_malloc(size_t size, size_t alignment) {
// 分配额外的空间用于对齐
void *ptr = malloc(size + alignment - 1);
if (!ptr) return NULL;

// 对齐地址
void *aligned = align_ptr(ptr, alignment);

// 存储原始指针
*((void **)aligned - 1) = ptr;

return aligned;
}

// 释放对齐的内存
void aligned_free(void *ptr) {
if (!ptr) return;

// 获取原始指针
void *original = *((void **)ptr - 1);
free(original);
}

实践练习

  1. 内存分配实验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 创建测试程序
cat > mem_test.c << EOL
#include <stdio.h>
#include <stdlib.h>

int main() {
// 分配内存
int *ptr = malloc(sizeof(int));
*ptr = 42;
printf("Value: %d\n", *ptr);
free(ptr);
return 0;
}
EOL

# 编译和运行
gcc mem_test.c -o mem_test
./mem_test
  1. 内存池实验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 创建内存池测试程序
cat > pool_test.c << EOL
#include <stdio.h>
#include "memory_pool.c"

int main() {
memory_pool_t *pool = create_pool();
if (!pool) return 1;

// 分配内存
int *ptr = pool_alloc(pool, sizeof(int));
*ptr = 100;
printf("Pool value: %d\n", *ptr);

free_pool(pool);
return 0;
}
EOL

# 编译和运行
gcc pool_test.c -o pool_test
./pool_test
  1. 内存对齐实验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建对齐测试程序
cat > align_test.c << EOL
#include <stdio.h>
#include "memory_align.c"

int main() {
// 分配对齐的内存
int *ptr = aligned_malloc(sizeof(int), 16);
*ptr = 200;
printf("Aligned value: %d\n", *ptr);

aligned_free(ptr);
return 0;
}
EOL

# 编译和运行
gcc align_test.c -o align_test
./align_test

思考题

  1. 内存管理的主要目标是什么?
  2. 常见的内存分配算法有哪些?
  3. 页式管理和段式管理的区别是什么?
  4. 什么是内存池?它有什么优点?
  5. 为什么需要内存对齐?

参考资料

  1. 《程序员的自我修养:链接、装载与库》
  2. Linux 内核文档
  3. System V ABI
  4. ELF 文件格式规范
  5. GNU Binutils 文档