在linux中每一个进程都认为自己拥有4G的内存空间,其中0-3G为自己独占,剩下的1G为内核所有。用户空间的额3G空间又分为代码段,数据段,堆栈段。其进程中的常数、全局变量和动态数据都存放在数据段中,子函数的入口变量、子程序的返回地址、局部变量存放于堆栈当中,当然程序代码就存放在代码段当中了。
那么这么多的数据内存是怎么来管理的呢?
我的OK6410开发板有256M的内存,然而一个进程需要4G的空间,怎么办?这就需要我们的内核去了解我们的实际内存是多少。所以内存一个任务是合理分配内存给要使用给的进程,当一个虚拟内存需要调用时,内核会把这段虚拟内存和实际的物理内存对应起来,当进程使用完成后,内核又会把这一对应关系给撤销掉,给另外的进程使用。
这里我们就引入了一个页的概念,页是内存管理的基本单位。因此我们这里需要提到一个MMU(内存管理器),一个页的大小为4KB,每个物理页都会对应一个struct page来保护。
分配内存的方法有多种,这里我介绍两种:
添加linux/slab.h头文件
1. void *kmalloc(size_t size, gfp_t flags); 用法跟malloc很相近。
a) 第一个参数为要分配内存的大小。
b) 第二个参数类型最常用的是GFP_KERNEL当没有可分配的内存时会引起睡眠,GFP_ATOMIC则不会引起睡眠.
void kfree(const void *objp)
使用完内存就要释放内存
添加linux/mm.h头文件
2. 是按页来分配内存
static inline struct page * alloc_pages(gfp_t gfp_mask, unsigned int order)
a) 第一个参数是类型最常用的是GFP_KERNEL当没有可分配的内存时会引起睡眠,GFP_ATOMIC则不会引起睡眠。
b) 第二个参数是分配的连续物理页大小是2的n次方,如果是1,则分配2页的连续内存即8KB。
c) 返回值是一个struct page的结构体,这个前提是在获得连续物理页的情况下,否则为NULL。
获得了物理地址我们并不能直接访问,必须转化为我们进程可以使用的虚拟地址
void *page_address(struct page *page)用来将实际的物理地址转换为虚拟地址。
当使用完这些内存之后我们就要释放内存
void __free_pages(struct page *page, unsigned int order)