1.页
内核把物理页作为内存管理的基本单元,并用struct page结构表示系统中的每个物理页。
struct page{
unsigned long flags;
atomic_t _count;
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping;
pgoff_t index;
struct list_head lru;
void *virtual;
}
flag表示页的状态
_count表示引用次数,为负值时表示空闲,可以调用page_count查询_count值,返回0表示空闲
virtual表示页的虚拟地址。高端内存中,动态映射时,该值为NULL。
lru 表示页面回收的LRU链表算法
2.区
Linux把系统的页划分为区,形成不同的内存池,可以根据用途进行分配。具体的分区要看不同的硬件体系架构,常用的分区为:ZONE_NORMAL,ZONE_HIGHMEM,ZONE_DMA;每个区都用struct zone表示:
struct zone {
unsigned long watermark[NR_WMARK];
unsigned long percpu_drift_mark;
unsigned long lowmem_reserve[MAX_NR_ZONES];
unsigned long dirty_balance_reserve;
#ifdef CONFIG_NUMA
int node;
unsigned long min_unmapped_pages;
unsigned long min_slab_pages;
#endif
struct per_cpu_pageset __percpu *pageset;
spinlock_t lock;
int all_unreclaimable; /* All pages pinned */
#ifdef CONFIG_MEMORY_HOTPLUG
/* see spanned/present_pages for more description */
seqlock_t span_seqlock;
#endif
struct free_area free_area[MAX_ORDER];
#ifndef CONFIG_SPARSEMEM
unsigned long *pageblock_flags;
#endif /* CONFIG_SPARSEMEM */
#ifdef CONFIG_COMPACTION
unsigned int compact_considered;
unsigned int compact_defer_shift;
int compact_order_failed;
#endif
ZONE_PADDING(_pad1_)
spinlock_t lru_lock;
struct lruvec lruvec;
struct zone_reclaim_stat reclaim_stat;
unsigned long pages_scanned; /* since last reclaim */
unsigned long flags; /* zone flags, see below */
atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
unsigned int inactive_ratio;
ZONE_PADDING(_pad2_)
wait_queue_head_t * wait_table;
unsigned long wait_table_hash_nr_entries;
unsigned long wait_table_bits;
struct pglist_data *zone_pgdat;
unsigned long zone_start_pfn;
unsigned long spanned_pages; /* total size, including holes */
unsigned long present_pages; /* amount of memory (excluding holes) */
const char *name;
} ____cacheline_internodealigned_in_smp;
其中watermark数组持有该区的最小值、最低和最高水位,分别为:WMARK_MIN,WMARK_LOW和WMARK_HIGH
3.获得页
内核提供了请求内存的底层机制。核心函数是:alloc_pages(gfp_mask, order)
#define alloc_pages(gfp_mask, order) \
alloc_pages_node(numa_node_id(), gfp_mask, order)
static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
unsigned int order)
{
/* Unknown node is current node */
if (nid < 0)
nid = numa_node_id();
return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
}
__alloc_pages(gfp_t gfp_mask, unsigned int order,
struct zonelist *zonelist)
{
return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
}
alloc_pages最终调用的是_alloc_pages_nodemask,后面会仔细分析。alloc_pages返回的是page结构体,可以用page_address函数转换成对应的逻辑地址。
#define page_address(page) ((page)->virtual)
如果无需用到struct page结构体,可以直接调用_get_free_pages