From 72bdd225644f39ed505463e4a2f26714e0e3d08d Mon Sep 17 00:00:00 2001 From: "rick.chan" Date: Tue, 15 Dec 2020 10:27:40 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=20page=20=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=87=BD=E6=95=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: rick.chan --- .../Linux/Kernel/API/Linux_Kernel_内存分配.md | 207 +++++++++++++++--- 1 file changed, 182 insertions(+), 25 deletions(-) diff --git a/Software/Development/OperatingSystem/Linux/Kernel/API/Linux_Kernel_内存分配.md b/Software/Development/OperatingSystem/Linux/Kernel/API/Linux_Kernel_内存分配.md index a51431f..50d714c 100644 --- a/Software/Development/OperatingSystem/Linux/Kernel/API/Linux_Kernel_内存分配.md +++ b/Software/Development/OperatingSystem/Linux/Kernel/API/Linux_Kernel_内存分配.md @@ -1,6 +1,178 @@ -# Linux Kernel 内存分配 +# Linux Kernel 内存管理 -## kmalloc/kzalloc/kfree +## 1.page + +**头文件:** + +```cpp +#include +``` + +### 1.1.get_zeroed_page + +**函数原型:** + +```c +unsigned long get_zeroed_page(gfp_t gfp_mask); +``` + +**说明:** + +该函数返回一个指向新页的虚拟地址指针并且将该页清零。 + +**参数:** + +gfp_mask:要分配内存的类型。 + +较常用的 gfp_mask(分配内存的方法)如下: + +* GFP_ATOMIC —— 分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断; +* GFP_KERNEL —— 正常分配内存; +* GFP_DMA —— 给 DMA 控制器分配内存,需要使用该标志(DMA要求分配虚拟地址和物理地址连续)。 + +gfp_mask 的参考用法: + +| 说民 | Flag | +|-----------------------|-----------------------| +| 进程上下文,可以睡眠 | GFP_KERNEL | +| 进程上下文,不可以睡眠(中断处理程序、软中断、Tasklet) | GFP_ATOMIC | +| 用于DMA的内存,可以睡眠 | GFP_DMA \| GFP_KERNEL | +| 用于DMA的内存,不可以睡眠 | GFP_DMA \|GFP_ATOMIC | + +**返回值:** + +申请成功返回有效的内存首地址值,失败返回 0。 + +### 1.2.__get_free_pages + +**函数原型:** + +```c +unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); +``` + +**说明:** + +该函数可分配多个连续的页并返回分配内存的首地址,分配的页数为 2order,分配的页不清零。order 允许的最大值是 10(即 1024 页)或者 11(即 2048 页),依赖于具体的硬件平台。 + +**参数:** + +gfp_mask:与 get_zeroed_page 中的 gfp_mask 一致; + +order:要分配的页数。 + +**返回值:** + +申请成功返回有效的内存首地址值,失败返回 0。 + +### 1.3.alloc_pages + +**函数原型:** + +```c +struct page *alloc_pages(gfp_t gfp_mask, unsigned int order); +``` + +**说明:** + +与 __get_free_pages 函数一样可分配多个连续的页,但它返回分配的第一个页的描述符而非首地址。分配的页数为 2order,分配的页不清零。order 允许的最大值是 10(即 1024 页)或者 11(即 2048 页),依赖于具体的硬件平台。 + +**参数:** + +gfp_mask:与 get_zeroed_page 中的 gfp_mask 一致; + +order:要分配的页数。 + +**返回值:** + +申请成功返回有效的内存首地址,失败返回 NULL。 + +### 1.4.free_pages/__free_pages + +**函数原型:** + +```c +void __free_pages(struct page *page, unsigned int order); +void free_pages(unsigned long addr, unsigned int order); +``` + +**说明:** + +用 get_zeroed_page/__get_free_pages 分配的内存页用 free_pages 释放,用 alloc_pages 分配的页用 free_pages 释放。 + +**参数:** + +page/addr:要释放的内存首地址; + +order:要释放的页面数。 + +**返回值:** + +无 + +### 1.5.virt_to_page + +**函数原型:** + +```c +#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr)) +``` + +**说明:** + +将虚拟页面地址转换为页的描述符。 + +**参数:** + +kaddr:内核虚拟地址。 + +**返回值:** + +struct page* 类型的页面描述符。 + +## 2.reserved + +### 2.1.mark_page_reserved + +**函数原型:** + +```c +void mark_page_reserved(struct page *page); +``` + +**说明:** + +标记内存页为 reserved,避免被换出到外存。 + +**参数:** + +page:要标记为 reserved 的内存页。 + +**返回值:** + +无 + +### 2.2.free_reserved_page + +**函数原型:** + +```c +void free_reserved_page(struct page *page); +``` + +**说明:** + +释放 reserved 内存。 + +**参数:** + +page:要释放的 reserved 内存页。 + +**返回值:** + +无 + +## 3.kmalloc/kzalloc/kfree 通过 kmalloc/kzalloc 分配内核空间,通过 kfree 释放。 @@ -10,7 +182,7 @@ #include ``` -### kmalloc +### 3.1.kmalloc **函数原型:** @@ -26,28 +198,13 @@ kmalloc() 申请的内存位于物理内存映射区域,而且在物理上也 size:要分配的内存大小,以字节为单位; -flags:要分配内存的类型。 - -较常用的 flags(分配内存的方法)如下: - -* GFP_ATOMIC —— 分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断; -* GFP_KERNEL —— 正常分配内存; -* GFP_DMA —— 给 DMA 控制器分配内存,需要使用该标志(DMA要求分配虚拟地址和物理地址连续)。 - -flags 的参考用法: - -| 说民 | Flag | -|-----------------------|-----------------------| -| 进程上下文,可以睡眠 | GFP_KERNEL | -| 进程上下文,不可以睡眠(中断处理程序、软中断、Tasklet) | GFP_ATOMIC | -| 用于DMA的内存,可以睡眠 | GFP_DMA \| GFP_KERNEL | -| 用于DMA的内存,不可以睡眠 | GFP_DMA \|GFP_ATOMIC | +flags:与 gfp_mask 含义一致。 **返回值:** 申请成功返回有效的内存首地址,失败返回 NULL。 -### kzalloc +### 3.2.kzalloc **函数原型:** @@ -77,7 +234,7 @@ flags:要分配内存的类型。 申请成功返回有效的内存首地址,失败返回 NULL。 -### kfree +### 3.3.kfree **函数原型:** @@ -97,11 +254,11 @@ addr:要释放的内存首地址指针。 无 -## vmalloc/vfree +## 4.vmalloc/vfree 通过 vmalloc 分配内核空间,通过 vfree 释放。可以分配较大内存。使用 vmalloc 最著名的实例是内核对模块的实现,当模块被动态加载到内核当中时,就把模块装载到由 vmalloc() 分配的内存上。注意:vmalloc() 和 vfree() 可以睡眠,因此不能从中断上下文调用。 -### vmalloc +### 4.1.vmalloc **函数原型:** @@ -121,7 +278,7 @@ size:要分配的内存大小,以字节为单位。 申请成功返回有效的内存首地址,失败返回 NULL。 -### vfree +### 4.2.vfree **函数原型:** @@ -141,7 +298,7 @@ addr:要释放的内存首地址指针。 无 -## kmalloc/kzalloc/vmalloc 的比较 +## 5.kmalloc/kzalloc/vmalloc 的比较 kmalloc()、kzalloc()、vmalloc() 的共同特点是: