- 内核把物理页作为内存管理的基本单位,内核用一个page结构体表示内核中的每个物理页。
- Linux把系统的页划分为区,形成不同的内存池,根据用途分配。区只是内核为了管理页而采用的一种逻辑上的分组。
- 一些分配释放相关函数
- alloc_pages,该函数分配连续的物理页,返回一个指针指向第一个页的page结构体。free_pages做释放。
- kmalloc用来获得以字节为单位的一块内存。kfree做释放。
- vmalloc工作方式类似kmalloc,不过,vmalloc分配的内存在逻辑上是连续的而物理上则不连续。kmalloc确保在物理上是连续的。
- slab层:扮演的通用数据结构层缓存的角色,在物理内存中拿出一部分作为缓存。slab试图在以下几个基本原则间寻找一种平衡。
- 频繁使用的数据结构也会频繁分配和释放,应当缓存它们。
- 频繁的分配和回收必然会导致内存碎片,空闲链表的缓存会连续的存放,不会导致碎片。
- 回收的对象可以立即进行下一次分配。
- 如果分配器知道对象大小,页大小和总的高速缓存的大小这样的概念,它会做出更明确的抉择。
- 如果让部分缓存专属某个处理器,那么分配和释放就可以在不加SMP锁的情况下进行等。使用每个CPU数据的好处减少了数据锁定和减少缓存失效。
- slab 层把不同的对象划分为高速缓存组,其中每个高速缓存组都存放不同类型的对象。每种类型对象都对应一种高速缓存。比如inode,等常分配和释放的结构可以对应两个缓存组。
- kmalloc 建立在slab层之上,使用了一组通用缓存。
- 当你创建了一个高速缓存后,slab层所起的作用就像一个专用的分配器,可以为具体的对象类型进行分配。如果你要频繁的创建很多类型相同的对象,那么你就应该考虑使用slab高速缓存。
- 在栈上静态分配,用户空间可以负担起非常大的栈,而且栈空间还可以动态增长。而内核栈一般只有一两页。
- 分配函数的选择
- 如果你需要连续的物理页,就可以使用某个低级页分配器或kmalloc。这是内核中内存分配的常用方式。
- 如果你想从高端内存进行分配,就使用alloc pages()。allocpages()函数返回一个指向struct page结构的指针,而不是一个指向某个逻辑地址的指针。因为高端内存很可能并没有被映射,因此,访问它的唯一方式就是通过相应的struct page结构。为了获得真正的指针,应该调用 kmap,把高端内存映射到内核的逻辑地址空间。
-
如果你不需要物理上连续的页,而仅仅需要虚拟地址上连续的页,那么就使用vmalloc(不
过要记住vmalloc()相对kmalloc()来说,有一定的性能损失)。vmalloc函数分配的内存虚地址是连续的,但它本身并不保证物理上的连续。这与用户空间的分配非常类似,也是把物理内存块映射到连续的逻辑地址空间上。 -
如果你要创建和撤销很多大的数据结构,那么考虑建立slab高速缓存。slab层会给每个处理
器维持一个对象高速缓存(空闲链表),这种高速缓存会极大地提高对象分配和回收的性能。slab层不是频繁地分配和释放内存,而是为你把事先分配好的对象存放到高速缓存中。当你需要一块新的内存来存放数据结构时,slab层一般无须另外去分配内存,而只需要从高速缓存中得到一个对象就可以了。