上次我们分析了Linux的启动过程和初始化过程,今天主要分析内存初始化和常见的内存分配方式。在start_kernel内核初始化函数中,一共调用了86个函数进行初始化,其中包括一个初始化内存的mm_init函数。start_kernel|--->mm_init|--->mem_initlinux4.14/init/main.c会在mem_init函数中初始化partnersystem和slaballocator。先说两个概念:外部碎片:有一块小内存,夹在两个大内存之间,这两个大内存已经分配给了进程。由于这块小内存太小,申请者无法使用,所以一直闲置。内部碎片:一个进程申请了一段内存,但是这个进程一直没有用完,最后一段内存一直没有被使用。为了解决这两个问题,伙伴系统和平板分配器应运而生。buddy系统解决外部碎片问题,slab分配器解决内部碎片问题。1.伙伴系统是基于页面分配的,一次分配多个页面,这样中间就不会夹着小内存了。2、slab分配器是按字节分配的,特别适合需要频繁分配几十个字节的结构体。我们经常使用的kmalloc是基于slaballocator的。3、其实所有分配方式的最底层都是合伙人制度。它首先分配一块大内存,然后slab从中分配小内存。具体分析可以参考链接:https://www.cnblogs.com/arnoldlu/p/8251333.html这里列出了常用的内存分配API接口。最常用的是malloc和kmalloc,区别是一个在用户空间,一个在内核空间,使用kmalloc需要注意竞争,需要指定flag。void*kmalloc(size_tsize,intflags);内核编程(驱动程序编程)一定要注意竞争问题,重要的数据或内存在使用前后都要加锁。在kmalloc的使用过程中,常用的flags有:GFP_KERNEL,GFP_ATOMIC,GFP_USER,GFP_HIGHUSER,GFP_NOIO,GFP_NOFS。前两个是最常用的。GFP_KERNEL的意思是在使用kmalloc分配内存的时候,如果内存准备不够,就会等待,也就是休眠。GFP_ATOMIC是指在使用kmalloc分配内存时,如果内存准备不足,会立即返回,不会导致睡眠,适合在中断上下文或进程上下文中使用。补充:1.在slab分配器的基础上,出现了slob和slub分配器。在大内存的大型多核系统中,一般使用slub分配器,而在非常小的嵌入式系统中,一般使用slob分配器(只有600多行代码)。2、有些人可能知道Linux有一个bootmemallocator。这是Linux初始化过程中的一个临时分配器。会在setup_arch函数中初始化,然后在mm_init中关闭。在伙伴系统出现之前只是暂时的。使用。bootmem分配器按块分配,粒度大,不够细,造成内存浪费。bootmem分配器只会存在于start_kernel函数和mm_init函数之前,中间函数会调用它进行内存分配。start_kernel|--->setup_arch|--->paging_init|--->bootmem_init
