技术交流

好好学习,天天向上。

0%

第八章——分配内存

说明

内存管理是操作系统的核心,在ldd3第八章仅介绍了kmalloc和vmalloc的用法,但是并没有过多的涉及其实现原理。后面会写一个较为细致的内存管理的笔记,作为本章笔记的补充。

per-cpu变量

per-cpu变量将会被内核放到一个特殊的内存段中。每个cpu都包含一份相同名称的变量,互不干扰,访问时几乎不用加锁。但在访问per-cpu变量是,要注意在关抢占的情况下完成所有的访问操作。注意,per-cpu不要求关中断,而要求关抢占。关抢占的意义是防止使用per-cpu的线程被调度到别的核心执行。

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
DEFINE_PER_CPU(type, name); // 定义一个常规的per-cpu变量
DEFINE_PER_CPU(int[3], my_percpu_array); // 可以是数组
void *alloc_percpu(type); // 动态的创建per-cpu变量
void *__alloc_percpu(size_t size, size_t align); // 动态创建per-cpu变量但是指定基地址对齐

/*
* Must be an lvalue. Since @var must be a simple identifier,
* we force a syntax error here if it isn't.
*/
#define get_cpu_var(var) \
(*({ \
preempt_disable(); \
this_cpu_ptr(&var); \
}))

/*
* The weird & is necessary because sparse considers (void)(var) to be
* a direct dereference of percpu variable (var).
*/
#define put_cpu_var(var) \
do { \
(void)&(var); \
preempt_enable(); \
} while (0)

// 还有指针访问形式,需要调用者手动禁止抢占,一般封装在get_put()和put_cpu()之间。
#define per_cpu(var, cpu) (*per_cpu_ptr(&(var), cpu)) // 访问指定CPU的per-cpu变量,需要用锁来保证安全

per-cpu变量可以像内核其他变量一样,导出符号

1
2
3
4
EXPORT_PER_CPU_SYMBOL(per_cpu_var); // 创建者导出
EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var);

CLARE_PER_CPU(type, name); // 使用者声明

大块内存分配

如果实在需要大块内存分配,对于模块可以使用mem=xxx,对于链接到内核的模块可以使用bootmem接口。通过bootmem分配的内存,不再由内核管理。

1
2
3
4
5
6
7
8
9
10
11
12
#include <linux/bootmem.h>
// Allocate size number of bytes from ZONE_NORMAL. The allocation will be aligned to the L1 hardware cache to get the maximum benefit from the hardware cache
void *alloc_bootmem(unsigned long size);

// Allocate size number of bytes from ZONE_DMA. The allocation will be aligned to the L1 hardware cache
void *alloc_bootmem_low(unsigned long size);

// Allocate size number of bytes from ZONE_NORMAL aligned on a page size so that full pages will be returned to the caller
void *alloc_bootmem_pages(unsigned long size);

// Allocate size number of bytes from ZONE_DMA aligned on a page size so that full pages will be returned to the caller
void *alloc_bootmem_low_pages(unsigned long size);