linux如何管理物理内存?
Posted Jello
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux如何管理物理内存?相关的知识,希望对你有一定的参考价值。
Linux kernel version: 5.0.1
arm64
1.将物理内存划分为若干页,每页的大小为4KiB(可以为8KiB或16KiB),那么如何知道每个页当前是什么情况呢?
那就需要一个结构体来描述每一页的情况,那么就出现了结构体struct page.
2.有若干页,意味着需要若干个struct page这样的结构体来描述若干页的状态;
3.这些struct page存放在哪里呢?肯定是存放在物理内存里;
4.存放在物理内存里,那么假设物理内存有4MiB,指定页面大小为4KiB,那么这些物理内存能被划分为多少个页面呢?又需要多少物理内存来存放struct page结构体呢?
页面个数=4MiB/4KiB=4*1024 KiB/4KiB=1024个;
那么就需要1024个struct page来描述这1024个页面的情况,这么多结构体需要多少内存呢?
1024 * sizeof(struct page)
5.如何获取sizeof(struct page)的大小呢?
struct page结构体(结构体定义在include/linux/mm_types.h)如下:
1 struct page { 2 unsigned long flags; /* Atomic flags, some possibly 3 * updated asynchronously */ 4 /* 5 * Five words (20/40 bytes) are available in this union. 6 * WARNING: bit 0 of the first word is used for PageTail(). That 7 * means the other users of this union MUST NOT use the bit to 8 * avoid collision and false-positive PageTail(). 9 */ 10 union { 11 struct { /* Page cache and anonymous pages */ 12 /** 13 * @lru: Pageout list, eg. active_list protected by 14 * zone_lru_lock. Sometimes used as a generic list 15 * by the page owner. 16 */ 17 struct list_head lru; 18 /* See page-flags.h for PAGE_MAPPING_FLAGS */ 19 struct address_space *mapping; 20 pgoff_t index; /* Our offset within mapping. */ 21 /** 22 * @private: Mapping-private opaque data. 23 * Usually used for buffer_heads if PagePrivate. 24 * Used for swp_entry_t if PageSwapCache. 25 * Indicates order in the buddy system if PageBuddy. 26 */ 27 unsigned long private; 28 }; 29 struct { /* slab, slob and slub */ 30 union { 31 struct list_head slab_list; /* uses lru */ 32 struct { /* Partial pages */ 33 struct page *next; 34 #ifdef CONFIG_64BIT 35 int pages; /* Nr of pages left */ 36 int pobjects; /* Approximate count */ 37 #else 38 short int pages; 39 short int pobjects; 40 #endif 41 }; 42 }; 43 struct kmem_cache *slab_cache; /* not slob */ 44 /* Double-word boundary */ 45 void *freelist; /* first free object */ 46 union { 47 void *s_mem; /* slab: first object */ 48 unsigned long counters; /* SLUB */ 49 struct { /* SLUB */ 50 unsigned inuse:16; 51 unsigned objects:15; 52 unsigned frozen:1; 53 }; 54 }; 55 }; 56 struct { /* Tail pages of compound page */ 57 unsigned long compound_head; /* Bit zero is set */ 58 59 /* First tail page only */ 60 unsigned char compound_dtor; 61 unsigned char compound_order; 62 atomic_t compound_mapcount; 63 }; 64 struct { /* Second tail page of compound page */ 65 unsigned long _compound_pad_1; /* compound_head */ 66 unsigned long _compound_pad_2; 67 struct list_head deferred_list; 68 }; 69 struct { /* Page table pages */ 70 unsigned long _pt_pad_1; /* compound_head */ 71 pgtable_t pmd_huge_pte; /* protected by page->ptl */ 72 unsigned long _pt_pad_2; /* mapping */ 73 union { 74 struct mm_struct *pt_mm; /* x86 pgds only */ 75 atomic_t pt_frag_refcount; /* powerpc */ 76 }; 77 #if ALLOC_SPLIT_PTLOCKS 78 spinlock_t *ptl; 79 #else 80 spinlock_t ptl; 81 #endif 82 }; 83 struct { /* ZONE_DEVICE pages */ 84 /** @pgmap: Points to the hosting device page map. */ 85 struct dev_pagemap *pgmap; 86 unsigned long hmm_data; 87 unsigned long _zd_pad_1; /* uses mapping */ 88 }; 89 90 /** @rcu_head: You can use this to free a page by RCU. */ 91 struct rcu_head rcu_head; 92 }; 93 94 union { /* This union is 4 bytes in size. */ 95 /* 96 * If the page can be mapped to userspace, encodes the number 97 * of times this page is referenced by a page table. 98 */ 99 atomic_t _mapcount; 100 101 /* 102 * If the page is neither PageSlab nor mappable to userspace, 103 * the value stored here may help determine what this page 104 * is used for. See page-flags.h for a list of page types 105 * which are currently stored here. 106 */ 107 unsigned int page_type; 108 109 unsigned int active; /* SLAB */ 110 int units; /* SLOB */ 111 }; 112 113 /* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */ 114 atomic_t _refcount; 115 116 #ifdef CONFIG_MEMCG 117 struct mem_cgroup *mem_cgroup; 118 #endif 119 120 /* 121 * On machines where all RAM is mapped into kernel address space, 122 * we can simply calculate the virtual address. On machines with 123 * highmem some memory is mapped into kernel virtual memory 124 * dynamically, so we need a place to store that address. 125 * Note that this field could be 16 bits on x86 ... ;) 126 * 127 * Architectures with slow multiplication can define 128 * WANT_PAGE_VIRTUAL in asm/page.h 129 */ 130 #if defined(WANT_PAGE_VIRTUAL) 131 void *virtual; /* Kernel virtual address (NULL if 132 not kmapped, ie. highmem) */ 133 #endif /* WANT_PAGE_VIRTUAL */ 134 135 #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS 136 int _last_cpupid; 137 #endif 138 } _struct_page_alignment;
使用此内核模块获取,编译方法为:make CROSS_COMPILE=1 KDIR=<linux kernel source code path>
所以:
1024 * sizeof(struct page) = 1024 * 64 = 64 KiB = 16 个页面
6.既然有部分物理内存用来存储每个页面的情况,那么可用的物理内存必然少于4MiB,那么具体是多少呢?
1024 - 16 = 1008 个页面 = 1008 * 4 KiB = 4032 KiB
以上是关于linux如何管理物理内存?的主要内容,如果未能解决你的问题,请参考以下文章
Linux 内核 内存管理物理分配页 ⑨ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | retry 标号代码分析 )