注:
1) __builtin_constant_p 编译器内联函数,判断传入参数是否为常量。如果是变量,直接调用 __kmalloc 函数。
2) KMALLOC_MAX_CACHE_SIZE 表示系统创建 slab cache 的最大值为8K,定义如下:
RockPI 4A Linux内核使能 ARM64_4K_PAGES 。可使用命令 getconf 查看 page size ,具体如下:
3) kmalloc 一般用于小内存分配,RockPI 4A Linux内核基于 slub ( CONFIG_SLUB=y )实现。系统先用页分配器分配以页为最小单位的连续物理地址,然后 kmalloc 在此基础上根据调用者的需要进行切分。如果分配超过 KMALLOC_MAX_CACHE_SIZE ,则使用 kmalloc_large 进行大内存分配,即调用页分配器分配内存。( 后续仔细学习 )
4) kmalloc 分配的内存在物理上连续,可用于DMA设备。 vmalloc 分配的内存是线性地址连续,物理地址不连续,不可用于DMA设备。
size :分配内存的大小,以字节为单位;
flags :分配内存的类型,包括:
1) GFP_USER :可能会引起休眠,用于为用户空间分配内存。
2) GFP_KERNEL :可能会引起休眠,用于内核内存正常分配。
3) GFP_ATOMIC :不会引起休眠,可用于中断处理程序中内存分配。
4) GFP_HIGHUSER :从高端内存中分配内存。
5) GFP_DMA :用于DMA内存分配。
6)其它类型见: include/linux/gfp.h
GFP 可理解为 get free page 。
返回分配内存的首地址,是虚拟地址(线性地址)。
正所谓有借有还,再借不难。每次 kmalloc ,都要有对应的内存释放函数 kfree 。定义文件: mm/slub.c ,如下:
/boot 分区是系统启动所需要的文件,就跟windows的C盘中的windows目录类似,这个分区中的文件并不大,只需要100M足够。Swap分区是交换分区,当内存不够时,系统会把这部分空间当内存使用。/ 分区,其实就是一个根目录,在以后的章节中会介绍到。现在不懂并没有关系,只要知道有这么一个东西即可。/data 这个分区是我们自定义的,就是专门放数据的分区。
如果你安装的是虚拟机,并且你只有8G的磁盘空间,那么我建议你这样分区:
1 /boot 100M
2 swap 内存的2倍
3 / 全部剩余空间更多Linux资讯可参考书籍《Linux就该这么学》。
*** 作系统的内存管理,主要分为三个方面。
第一,物理内存的管理,相当于会议室管理员管理会议室。
第二,虚拟地址的管理,也即在项目组的视角,会议室的虚拟地址应该如何组织。
第三,虚拟地址和物理地址如何映射,也即会议室管理员如果管理映射表。
那么虚拟地址和物理地址如何映射呢?
每一个进程都有一个列表vm_area_struct,指向虚拟地址空间的不同的内存块,这个变量的名字叫mmap。
其实内存映射不仅仅是物理内存和虚拟内存之间的映射,还包括将文件中的内容映射到虚拟内存空间。这个时候,访问内存空间就能够访问到文件里面的数据。而仅有物理内存和虚拟内存的映射,是一种特殊情况。
如果我们要申请小块内存,就用brk。brk函数之前已经解析过了,这里就不多说了。如果申请一大块内存,就要用mmap。对于堆的申请来讲,mmap是映射内存空间到物理内存。
另外,如果一个进程想映射一个文件到自己的虚拟内存空间,也要通过mmap系统调用。这个时候mmap是映射内存空间到物理内存再到文件。可见mmap这个系统调用是核心,我们现在来看mmap这个系统调用。
用户态的内存映射机制包含以下几个部分。
物理内存根据NUMA架构分节点。每个节点里面再分区域。每个区域里面再分页。
物理页面通过伙伴系统进行分配。分配的物理页面要变成虚拟地址让上层可以访问,kswapd可以根据物理页面的使用情况对页面进行换入换出。
对于内存的分配需求,可能来自内核态,也可能来自用户态。
对于内核态,kmalloc在分配大内存的时候,以及vmalloc分配不连续物理页的时候,直接使用伙伴系统,分配后转换为虚拟地址,访问的时候需要通过内核页表进行映射。
对于kmem_cache以及kmalloc分配小内存,则使用slub分配器,将伙伴系统分配出来的大块内存切成一小块一小块进行分配。
kmem_cache和kmalloc的部分不会被换出,因为用这两个函数分配的内存多用于保持内核关键的数据结构。内核态中vmalloc分配的部分会被换出,因而当访问的时候,发现不在,就会调用do_page_fault。
对于用户态的内存分配,或者直接调用mmap系统调用分配,或者调用malloc。调用malloc的时候,如果分配小的内存,就用sys_brk系统调用;如果分配大的内存,还是用sys_mmap系统调用。正常情况下,用户态的内存都是可以换出的,因而一旦发现内存中不存在,就会调用do_page_fault。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)