物理内存的组织方式:每个页面都有一个结构,每一个都有节点( 三 )
也正是因为 slab allocator 对于队列的维护过于复杂,后来就有了一种不使用队列的分配器 slub allocator,后面我们会解析这个分配器 。但是你会发现,它里面还是用了很多 slab 的字眼,因为它保留了 slab 的用户接口,可以看成 slab allocator 的另一种实现 。
还有一种小块内存的分配器称为slob,非常简单,主要使用在小型的嵌入式系统 。
如果某一页是用于分割成一小块一小块的内存进行分配的使用模式,则会使用 union 中的以下变量:
- s_mem 是已经分配了正在使用的 slab 的第一个对象;
- freelist 是池子中的空闲对象;
- rcu_head 是需要释放的列表 。
struct page {unsigned long flags;union {struct address_space *mapping;void *s_mem;/* slab first object */atomic_t compound_mapcount; /* first tail page */};union {pgoff_t index;/* Our offset within mapping. */void *freelist;/* sl[aou]b first free object */};union {unsigned counters;struct {union {atomic_t _mapcount;unsigned int active;/* SLAB */struct {/* SLUB */unsigned inuse:16;unsigned objects:15;unsigned frozen:1;};int units;/* SLOB */};atomic_t _refcount;};};union {struct list_head lru; /* Pageout list*/struct dev_pagemap *pgmap;struct {/* slub per cpu partial pages */struct page *next; /* Next partial slab */int pages; /* Nr of partial slabs left */int pobjects; /* Approximate # of objects */};struct rcu_head rcu_head;struct {unsigned long compound_head; /* If bit zero is set */unsigned int compound_dtor;unsigned int compound_order;};};union {unsigned long private;struct kmem_cache *slab_cache; /* SL[AU]B: Pointer to slab */};......}
页的分配好了,前面我们讲了物理内存的组织,从节点到区域到页到小块 。接下来,我们来看物理内存的分配 。对于要分配比较大的内存,例如到分配页级别的,可以使用伙伴系统(Buddy System) 。
Linux 中的内存管理的“页”大小为 4KB 。把所有的空闲页分组为 11 个页块链表,每个块链表分别包含很多个大小的页块,有 1、2、4、8、16、32、64、128、256、512 和 1024 个连续页的页块 。最大可以申请 1024 个连续页,对应 4MB 大小的连续内存 。每个页块的第一个页的物理地址是该页块大小的整数倍 。

文章插图
第 i 个页块链表中,页块中页的数目为 2^i 。
在 struct zone 里面有以下的定义:
struct free_area free_area[MAX_ORDER];
MAX_ORDER 就是指数 。#define MAX_ORDER 11
当向内核请求分配 (2^(i-1),2^i] 数目的页块时,按照 2^i 页块请求处理 。如果对应的页块链表中没有空闲页块,那我们就在更大的页块链表中去找 。当分配的页块中有多余的页时,伙伴系统会根据多余的页块大小插入到对应的空闲页块链表中 。例如,要请求一个 128 个页的页块时,先检查 128 个页的页块链表是否有空闲块 。如果没有,则查 256 个页的页块链表;如果有空闲块的话,则将 256 个页的页块分成两份,一份使用,一份插入 128 个页的页块链表中 。如果还是没有,就查 512 个页的页块链表;如果有的话,就分裂为 128、128、256 三个页块,一个 128 的使用,剩余两个插入对应页块链表 。
上面这个过程,我们可以在分配页的函数 alloc_pages 中看到 。
static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order){ return alloc_pages_current(gfp_mask, order);}/** *alloc_pages_current - Allocate pages. * * @gfp: *%GFP_USERuser allocation, *%GFP_KERNEL kernel allocation, *%GFP_HIGHMEM highmem allocation, *%GFP_FSdon't call back into a file system. *%GFP_ATOMIC don't sleep. * @order: Power of two of allocation size in pages. 0 is a single page. * * Allocate a page from the kernel page pool.When not in * interrupt context and apply the current process NUMA policy. * Returns NULL when no page can be allocated. */struct page *alloc_pages_current(gfp_t gfp, unsigned order){ struct mempolicy *pol = &default_policy; struct page *page;...... page = __alloc_pages_nodemask(gfp, order,policy_node(gfp, pol, numa_node_id()),policy_nodemask(gfp, pol));...... return page;}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PPPoE报文交互详解
- 菜鸡程序员的一天都在折腾些什么?
- 滇红中国红茶叶,滇红茶叶的历史
- 越南酒店里的红茶,红茶的发展历史和状况
- 一个基于Vue3的无编译小框架 byview
- 英国人喝红茶的历史,锡兰茶的名与他的什么特点
- 功夫红茶得历史,功夫红茶历史
- 17 个高频好用的JavaScript 代码块
- 斯里兰卡比较好的红茶,斯里兰卡红茶历史
- 红茶茶艺表演解说,宣州名优茶的历史与特点