linux内核把物理页作为内存管理的基本单位。MMU通常是以页为单位来查找页表,内核用 struct page结构体来表示系统的每个页。不同的体系支持的页大小不同。arm64处理器支持3种页长度:4KB、16KB、64KB。
linux内核将整个物理内存按照页对齐方式划分成千上万个页进行管理。由于一个物理页用一个struct page表示,那么系统会有成千上万个struct page结构体,这些结构体也会占用实际的物理内存。因此,内核选择用union联合体来减少内存的使用。
在linux内核版本5.0中,page结构体成员如下:
struct page {
unsigned long flags; /* Atomic flags, some possibly
* updated asynchronously */
/*
* Five words (20/40 bytes) are available in this union.
* WARNING: bit 0 of the first word is used for PageTail(). That
* means the other users of this union MUST NOT use the bit to
* avoid collision and false-positive PageTail().
*/
union {
struct { /* Page cache and anonymous pages */
/**
* @lru: Pageout list, eg. active_list protected by
* zone_lru_lock. Sometimes used as a generic list
* by the page owner.
*/
struct list_head lru;
/* See page-flags.h for PAGE_MAPPING_FLAGS */
struct address_space *mapping;
pgoff_t index; /* Our offset within mapping. */
/**
* @private: Mapping-private opaque data.
* Usually used for buffer_heads if PagePrivate.
* Used for swp_entry_t if PageSwapCache.
* Indicates order in the buddy system if PageBuddy.
*/
unsigned long private;
};
struct { /* slab, slob and slub */
union {
struct list_head slab_list; /* uses lru */
struct { /* Partial pages */
struct page *next;
#ifdef CONFIG_64BIT
int pages; /* Nr of pages left */
int pobjects; /* Approximate count */
#else
short int pages;
short int pobjects;
#endif
};
};
struct kmem_cache *slab_cache; /* not slob */
/* Double-word boundary */
void *freelist; /* first free object */
union {
void *s_mem; /* slab: first object */
unsigned long counters; /* SLUB */
struct { /* SLUB */
unsigned inuse:16;
unsigned objects:15;
unsigned frozen:1;
};
};
};
struct { /* Tail pages of compound page */
unsigned long compound_head; /* Bit zero is set */
/* First tail page only */
unsigned char compound_dtor;
unsigned char compound_order;
atomic_t compound_mapcount;
};
struct { /* Second tail page of compound page */
unsigned long _compound_pad_1; /* compound_head */
unsigned long _compound_pad_2;
struct list_head deferred_list;
};
struct { /* Page table pages */
unsigned long _pt_pad_1; /* compound_head */
pgtable_t pmd_huge_pte; /* protected by page->ptl */
unsigned long _pt_pad_2; /* mapping */
union {
struct mm_struct *pt_mm; /* x86 pgds only */
atomic_t pt_frag_refcount; /* powerpc */
};
#if ALLOC_SPLIT_PTLOCKS
spinlock_t *ptl;
#else
spinlock_t ptl;
#endif
};
struct { /* ZONE_DEVICE pages */
/** @pgmap: Points to the hosting device page map. */
struct dev_pagemap *pgmap;
unsigned long hmm_data;
unsigned long _zd_pad_1; /* uses mapping */
};
/** @rcu_head: You can use this to free a page by RCU. */
struct rcu_head rcu_head;
};
union { /* This union is 4 bytes in size. */
/*
* If the page can be mapped to userspace, encodes the number
* of times this page is referenced by a page table.
*/
atomic_t _mapcount;
/*
* If the page is neither PageSlab nor mappable to userspace,
* the value stored here may help determine what this page
* is used for. See page-flags.h for a list of page types
* which are currently stored here.
*/
unsigned int page_type;
unsigned int active; /* SLAB */
int units; /* SLOB */
};
/* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */
atomic_t _refcount;
#ifdef CONFIG_MEMCG
struct mem_cgroup *mem_cgroup;
#endif
/*
* On machines where all RAM is mapped into kernel address space,
* we can simply calculate the virtual address. On machines with
* highmem some memory is mapped into kernel virtual memory
* dynamically, so we need a place to store that address.
* Note that this field could be 16 bits on x86 ... ;)
*
* Architectures with slow multiplication can define
* WANT_PAGE_VIRTUAL in asm/page.h
*/
#if defined(WANT_PAGE_VIRTUAL)
void *virtual; /* Kernel virtual address (NULL if
not kmapped, ie. highmem) */
#endif /* WANT_PAGE_VIRTUAL */
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
int _last_cpupid;
#endif
} _struct_page_alignment;
通过crash工具查看,page结构体大小占64bytes:
crash> struct page -o
struct page {
[0] unsigned long flags;
union {
struct {
[8] struct list_head lru;
[24] struct address_space *mapping;
[32] unsigned long index;
[40] unsigned long private;
};
struct {
union {
[8] struct list_head slab_list;
struct {
[8] struct page *next;
[16] int pages;
[20] int pobjects;
};
};
[24] struct kmem_cache *slab_cache;
[32] void *freelist;
union {
[40] void *s_mem;
[40] unsigned long counters;
struct {
[40] unsigned int inuse : 16;
[42] unsigned int objects : 15;
[43] unsigned int frozen : 1;
};
};
};
struct {
[8] unsigned long compound_head;
[16] unsigned char compound_dtor;
[17] unsigned char compound_order;
[20] atomic_t compound_mapcount;
};
struct {
[8] unsigned long _compound_pad_1;
[16] unsigned long _compound_pad_2;
[24] struct list_head deferred_list;
};
struct {
[8] unsigned long _pt_pad_1;
[16] pgtable_t pmd_huge_pte;
[24] unsigned long _pt_pad_2;
union {
[32] struct mm_struct *pt_mm;
[32] atomic_t pt_frag_refcount;
};
[40] spinlock_t ptl;
};
struct {
[8] struct dev_pagemap *pgmap;
[16] unsigned long hmm_data;
[24] unsigned long _zd_pad_1;
};
[8] struct callback_head callback_head;
};
union {
[48] atomic_t _mapcount;
[48] unsigned int page_type;
[48] unsigned int active;
[48] int units;
};
[52] atomic_t _refcount;
[56] struct mem_cgroup *mem_cgroup;
}
SIZE: 64
page结构体每个字段的含义: www.processon.com/view/link/6…