感谢支持
我们一直在努力

Linux物理内存描述

linux使用于广泛的体系结构,因此需要用一种与体系结构无关的方式来描述内存。linux用VM描述和管理内存。在VM中兽药的普遍概念就是非一致内存访问。对于大型机器而言,内存会分成许多簇,依据簇与处理器“距离”的不同,访问不同的簇会有不同的代价。


每个簇都被认为是一个节点(pg_data_t),每个节点被分成很多的成为管理区(zone)的块,用于表示内存中的某个范围。除了ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM以外,linux2.6.32中引入了ZONE_MOVABLE,用于适应大块连续内存的分配。


每个物理页面由一个page结构体描述,所有的结构都存储在一个全局的mem_map数组中(非平板模式),该数组通常存放在ZONE_NORMAL的首部,或者就在校内存系统中为装入内核映像而预留的区域之后。


节点


内存的每个节点都有pg_data_t描述,在分配一个页面时,linux采用节点局部分配的策略,从最靠近运行中的CPU的节点分配内存。由于进程往往是在同一个CPU上运行,因此从当前节点得到的内存很可能被用到。


  1. /* 

  2.  * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM 

  3.  * (mostly NUMA machines?) to denote a higher-level memory zone than the 

  4.  * zone denotes. 

  5.  * 

  6.  * On NUMA machines, each NUMA node would have a pg_data_t to describe 

  7.  * it’s memory layout. 

  8.  * 

  9.  * Memory statistics and page replacement data structures are maintained on a 

  10.  * per-zone basis. 

  11.  */  

  12. struct bootmem_data;  

  13. typedef struct pglist_data {  

  14.      /*该节点内的内存区。可能的区域类型用zone_type表示。 */  

  15.     struct zone node_zones[MAX_NR_ZONES];  

  16.      /* 该节点的备用内存区。当节点没有可用内存时,就从备用区中分配内存。*/  

  17.     struct zonelist node_zonelists[MAX_ZONELISTS];  

  18.       /*可用内存区数目,即node_zones数据中保存的最后一个有效区域的索引*/  

  19.     int nr_zones;  

  20. #ifdef CONFIG_FLAT_NODE_MEM_MAP /* means !SPARSEMEM */   

  21.      /* 在平坦型的内存模型中,它指向本节点第一个页面的描述符。 */  

  22.     struct page *node_mem_map;  

  23. #ifdef CONFIG_CGROUP_MEM_RES_CTLR   

  24.     /*cgroup相关*/  

  25.     struct page_cgroup *node_page_cgroup;  

  26. #endif   

  27. #endif   

  28.   /** 

  29.           * 在内存子系统初始化以前,即boot阶段也需要进行内存管理。 

  30.           * 此结构用于这个阶段的内存管理。 

  31.           */  

  32.     struct bootmem_data *bdata;  

  33. #ifdef CONFIG_MEMORY_HOTPLUG   

  34.     /* 

  35.      * Must be held any time you expect node_start_pfn, node_present_pages 

  36.      * or node_spanned_pages stay constant.  Holding this will also 

  37.      * guarantee that any pfn_valid() stays that way. 

  38.      * 

  39.      * Nests above zone->lock and zone->size_seqlock. 

  40.      */  

  41.         /*当系统支持内存热插拨时,用于保护本结构中的与节点大小相关的字段。 

  42.             哪调用node_start_pfn,node_present_pages,node_spanned_pages相关的代码时,需要使用该锁。 

  43.           */  

  44.     spinlock_t node_size_lock;  

  45. #endif   

  46.     /*起始页面帧号,指出该节点在全局mem_map中 

  47.     的偏移*/  

  48.     unsigned long node_start_pfn;  

  49.     unsigned long node_present_pages; /* total number of physical pages */  

  50.     unsigned long node_spanned_pages; /* total size of physical page range, including holes */  

  51.     /*节点编号*/                          

  52.     int node_id;  

  53.     /*等待该节点内的交换守护进程的等待队列。将节点中的页帧换出时会用到。*/  

  54.     wait_queue_head_t kswapd_wait;  

  55.     /*负责该节点的交换守��进程。*/  

  56.     struct task_struct *kswapd;  

  57.     /*由页交换子系统使用,定义要释放的区域大小。*/  

  58.     int kswapd_max_order;  

  59. } pg_data_t;  
管理区


每个管理区由一个zone结构体描述,对于管理区的类型描述如下


  1. enum zone_type {  

  2. #ifdef CONFIG_ZONE_DMA   

  3.     /* 

  4.      * ZONE_DMA is used when there are devices that are not able 

  5.      * to do DMA to all of addressable memory (ZONE_NORMAL). Then we 

  6.      * carve out the portion of memory that is needed for these devices. 

  7.      * The range is arch specific. 

  8.      * 

  9.      * Some examples 

  10.      * 

  11.      * Architecture     Limit 

  12.      * ————————— 

  13.      * parisc, ia64, sparc  <4G 

  14.      * s390         <2G 

  15.      * arm          Various 

  16.      * alpha        Unlimited or 0-16MB. 

  17.      * 

  18.      * i386, x86_64 and multiple other arches 

  19.      *          <16M. 

  20.      */  

  21.     ZONE_DMA,  

  22. #endif   

  23. #ifdef CONFIG_ZONE_DMA32   

  24.     /* 

  25.      * x86_64 needs two ZONE_DMAs because it supports devices that are 

  26.      * only able to do DMA to the lower 16M but also 32 bit devices that 

  27.      * can only do DMA areas below 4G. 

  28.      */  

  29.     ZONE_DMA32,  

  30. #endif   

  31.     /* 

  32.      * Normal addressable memory is in ZONE_NORMAL. DMA operations can be 

  33.      * performed on pages in ZONE_NORMAL if the DMA devices support 

  34.      * transfers to all addressable memory. 

  35.      */  

  36.     ZONE_NORMAL,  

  37. #ifdef CONFIG_HIGHMEM   

  38.     /* 

  39.      * A memory area that is only addressable by the kernel through 

  40.      * mapping portions into its own address space. This is for example 

  41.      * used by i386 to allow the kernel to address the memory beyond 

  42.      * 900MB. The kernel will set up special mappings (page 

  43.      * table entries on i386) for each page that the kernel needs to 

  44.      * access. 

  45.      */  

  46.     ZONE_HIGHMEM,  

  47. #endif   

  48.     /* 

  49.           这是一个伪内存段。为了防止形成物理内存碎片, 

  50.           可以将虚拟地址对应的物理地址进行迁移。 

  51.           */  

  52.     ZONE_MOVABLE,  

  53.     __MAX_NR_ZONES  

  54. };  
里面的英文注释已经写的很详细了。


管理区用于跟踪诸如页面使用情况统计数,空闲区域信息和锁信息等。


  1. struct zone {  

  2.     /* Fields commonly accessed by the page allocator */  

  3.   

  4.     /* zone watermarks, access with *_wmark_pages(zone) macros */  

  5.     /*本管理区的三个水线值:高水线(比较充足)、低水线、MIN水线。*/  

  6.     unsigned long watermark[NR_WMARK];  

  7.   

  8.     /* 

  9.      * We don’t know if the memory that we’re going to allocate will be freeable 

  10.      * or/and it will be released eventually, so to avoid totally wasting several 

  11.      * GB of ram we must reserve some of the lower zone memory (otherwise we risk 

  12.      * to run OOM on the lower zones despite there’s tons of freeable ram 

  13.      * on the higher zones). This array is recalculated at runtime if the 

  14.      * sysctl_lowmem_reserve_ratio sysctl changes. 

  15.      */  

  16.       /** 

  17.           * 当高端内存、normal内存区域中无法分配到内存时,需要从normal、DMA区域中分配内存。 

  18.           * 为了避免DMA区域被消耗光,需要额外保留一些内存供驱动使用。 

  19.           * 该字段就是指从上级内存区退到回内存区时,需要额外保留的内存数量。 

  20.           */  

  21.     unsigned long       lowmem_reserve[MAX_NR_ZONES];  

  22.   

  23. #ifdef CONFIG_NUMA   

  24.     /*所属的NUMA节点。*/  

  25.     int node;  

  26.     /* 

  27.      * zone reclaim becomes active if more unmapped pages exist. 

  28.      */  

  29.      /*当可回收的页超过此值时,将进行页面回收。*/  

  30.     unsigned long       min_unmapped_pages;  

  31.     /*当管理区中,用于slab的可回收页大于此值时,将回收slab中的缓存页。*/  

  32.     unsigned long       min_slab_pages;  

  33.     /* 

  34.           * 每CPU的页面缓存。 

  35.           * 当分配单个页面时,首先从该缓存中分配页面。这样可以: 

  36.           *避免使用全局的锁 

  37.           * 避免同一个页面反复被不同的CPU分配,引起缓存行的失效。 

  38.           * 避免将管理区中的大块分割成碎片。 

  39.           */  

  40.     struct per_cpu_pageset  *pageset[NR_CPUS];  

  41. #else   

  42.     struct per_cpu_pageset  pageset[NR_CPUS];  

  43. #endif   

  44.     /* 

  45.      * free areas of different sizes 

  46.      */  

  47.      /*该锁用于保护伙伴系统数据结构。即保护free_area相关数据。*/  

  48.     spinlock_t      lock;  

  49. #ifdef CONFIG_MEMORY_HOTPLUG   

  50.     /* see spanned/present_pages for more description */  

  51.     /*用于保护spanned/present_pages等变量。这些变量几乎不会发生变化,除非发生了内存热插拨操作。 

  52.            这几个变量并不被lock字段保护。并且主要用于读,因此使用读写锁。*/  

  53.     seqlock_t       span_seqlock;  

  54. #endif   

  55.     /*伙伴系统的主要变量。这个数组定义了11个队列,每个队列中的元素都是大小为2^n的页面*/  

  56.     struct free_area    free_area[MAX_ORDER];  

  57.   

  58. #ifndef CONFIG_SPARSEMEM   

  59.     /* 

  60.      * Flags for a pageblock_nr_pages block. See pageblock-flags.h. 

  61.      * In SPARSEMEM, this map is stored in struct mem_section 

  62.      */  

  63.      /*本管理区里的页面标志数组*/  

  64.     unsigned long       *pageblock_flags;  

  65. #endif /* CONFIG_SPARSEMEM */   

  66.   

  67.     /*填充的未用字段,确保后面的字段是缓存行对齐的*/  

  68.     ZONE_PADDING(_pad1_)  

  69.   

  70.     /* Fields commonly accessed by the page reclaim scanner */  

  71.     /* 

  72.           * lru相关的字段用于内存回收。这个字段用于保护这几个回收相关的字段。 

  73.           * lru用于确定哪些字段是活跃的,哪些不是活跃的,并据此确定应当被写回到磁盘以释放内存。 

  74.           */  

  75.     spinlock_t      lru_lock;     

  76.     /* 匿名活动页、匿名不活动页、文件活动页、文件不活动页链表头*/  

  77.     struct zone_lru {  

  78.         struct list_head list;  

  79.     } lru[NR_LRU_LISTS];  

  80.     /*页面回收状态*/  

  81.     struct zone_reclaim_stat reclaim_stat;  

  82.     /*自从最后一次回收页面以来,扫过的页面数*/  

  83.     unsigned long       pages_scanned;     /* since last reclaim */  

  84.     unsigned long       flags;         /* zone flags, see below */  

  85.   

  86.     /* Zone statistics */  

  87.     atomic_long_t       vm_stat[NR_VM_ZONE_STAT_ITEMS];  

  88.   

  89.     /* 

  90.      * prev_priority holds the scanning priority for this zone.  It is 

  91.      * defined as the scanning priority at which we achieved our reclaim 

  92.      * target at the previous try_to_free_pages() or balance_pgdat() 

  93.      * invokation. 

  94.      * 

  95.      * We use prev_priority as a measure of how much stress page reclaim is 

  96.      * under – it drives the swappiness decision: whether to unmap mapped 

  97.      * pages. 

  98.      * 

  99.      * Access to both this field is quite racy even on uniprocessor.  But 

  100.      * it is expected to average out OK. 

  101.      */  

  102.     int prev_priority;  

  103.   

  104.     /* 

  105.      * The target ratio of ACTIVE_ANON to INACTIVE_ANON pages on 

  106.      * this zone’s LRU.  Maintained by the pageout code. 

  107.      */  

  108.     unsigned int inactive_ratio;  

  109.   

  110.     /*为cache对齐*/  

  111.     ZONE_PADDING(_pad2_)  

  112.     /* Rarely used or read-mostly fields */  

  113.   

  114.     /* 

  115.      * wait_table       — the array holding the hash table 

  116.      * wait_table_hash_nr_entries   — the size of the hash table array 

  117.      * wait_table_bits  — wait_table_size == (1 << wait_table_bits) 

  118.      * 

  119.      * The purpose of all these is to keep track of the people 

  120.      * waiting for a page to become available and make them 

  121.      * runnable again when possible. The trouble is that this 

  122.      * consumes a lot of space, especially when so few things 

  123.      * wait on pages at a given time. So instead of using 

  124.      * per-page waitqueues, we use a waitqueue hash table. 

  125.      * 

  126.      * The bucket discipline is to sleep on the same queue when 

  127.      * colliding and wake all in that wait queue when removing. 

  128.      * When something wakes, it must check to be sure its page is 

  129.      * truly available, a la thundering herd. The cost of a 

  130.      * collision is great, but given the expected load of the 

  131.      * table, they should be so rare as to be outweighed by the 

  132.      * benefits from the saved space. 

  133.      * 

  134.      * __wait_on_page_locked() and unlock_page() in mm/filemap.c, are the 

  135.      * primary users of these fields, and in mm/page_alloc.c 

  136.      * free_area_init_core() performs the initialization of them. 

  137.      */  

  138.     wait_queue_head_t   * wait_table;  

  139.     unsigned long       wait_table_hash_nr_entries;  

  140.     unsigned long       wait_table_bits;  

  141.   

  142.     /* 

  143.      * Discontig memory support fields. 

  144.      */  

  145.      /*管理区属于的节点*/  

  146.     struct pglist_data  *zone_pgdat;  

  147.     /* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */  

  148.     /*管理区的页面在mem_map中的偏移*/  

  149.     unsigned long       zone_start_pfn;  

  150.   

  151.     /* 

  152.      * zone_start_pfn, spanned_pages and present_pages are all 

  153.      * protected by span_seqlock.  It is a seqlock because it has 

  154.      * to be read outside of zone->lock, and it is done in the main 

  155.      * allocator path.  But, it is written quite infrequently. 

  156.      * 

  157.      * The lock is declared along with zone->lock because it is 

  158.      * frequently read in proximity to zone->lock.  It’s good to 

  159.      * give them a chance of being in the same cacheline. 

  160.      */  

  161.     unsigned long       spanned_pages;  /* total size, including holes */  

  162.     unsigned long       present_pages;  /* amount of memory (excluding holes) */  

  163.   

  164.     /* 

  165.      * rarely used fields: 

  166.      */  

  167.     const char      *name;  

  168. } ____cacheline_internodealigned_in_smp;  
没有说明的地方,内核中的英文注释已经写得很清楚了。

页面


系统中每个物理页面都有一个相关联的page用于记录该页面的状态。


  1. /* 

  2.  * Each physical page in the system has a struct page associated with 

  3.  * it to keep track of whatever it is we are using the page for at the 

  4.  * moment. Note that we have no way to track which tasks are using 

  5.  * a page, though if it is a pagecache page, rmap structures can tell us 

  6.  * who is mapping it. 

  7.  */  

  8. struct page {  

  9.     unsigned long flags;        /* Atomic flags, some possibly 

  10.                      * updated asynchronously */  

  11.     atomic_t _count;        /* Usage count, see below. */  

  12.     union {  

  13.         atomic_t _mapcount; /* Count of ptes mapped in mms, 

  14.                      * to show when page is mapped 

  15.                      * & limit reverse map searches. 

  16.                      */  

  17.         struct {        /* SLUB */  

  18.             u16 inuse;  

  19.             u16 objects;  

  20.         };  

  21.     };  

  22.     union {  

  23.         struct {  

  24.         unsigned long private;      /* Mapping-private opaque data: 

  25.                          * usually used for buffer_heads 

  26.                          * if PagePrivate set; used for 

  27.                          * swp_entry_t if PageSwapCache; 

  28.                          * indicates order in the buddy 

  29.                          * system if PG_buddy is set. 

  30.                          */  

  31.         struct address_space *mapping;  /* If low bit clear, points to 

  32.                          * inode address_space, or NULL. 

  33.                          * If page mapped as anonymous 

  34.                          * memory, low bit is set, and 

  35.                          * it points to anon_vma object: 

  36.                          * see PAGE_MAPPING_ANON below. 

  37.                          */  

  38.         };  

  39. #if USE_SPLIT_PTLOCKS   

  40.         spinlock_t ptl;  

  41. #endif   

  42.         struct kmem_cache *slab;    /* SLUB: Pointer to slab */  

  43.     /* 如果属于伙伴系统,并且不是伙伴系统中的第一个页 

  44.     则指向第一个页*/  

  45.         struct page *first_page;    /* Compound tail pages */  

  46.     };  

  47.     union {/*如果是文件映射,那么表示本页面在文件中的位置(偏移)*/  

  48.         pgoff_t index;      /* Our offset within mapping. */  

  49.         void *freelist;     /* SLUB: freelist req. slab lock */  

  50.     };  

  51.     struct list_head lru;       /* Pageout list, eg. active_list 

  52.                      * protected by zone->lru_lock ! 

  53.                      */  

  54.     /* 

  55.      * On machines where all RAM is mapped into kernel address space, 

  56.      * we can simply calculate the virtual address. On machines with 

  57.      * highmem some memory is mapped into kernel virtual memory 

  58.      * dynamically, so we need a place to store that address. 

  59.      * Note that this field could be 16 bits on x86 … 😉 

  60.      * 

  61.      * Architectures with slow multiplication can define 

  62.      * WANT_PAGE_VIRTUAL in asm/page.h 

  63.      */  

  64. #if defined(WANT_PAGE_VIRTUAL)   

  65.     void *virtual;          /* Kernel virtual address (NULL if 

  66.                        not kmapped, ie. highmem) */  

  67. #endif /* WANT_PAGE_VIRTUAL */   

  68. #ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS   

  69.     unsigned long debug_flags;  /* Use atomic bitops on this */  

  70. #endif   

  71.   

  72. #ifdef CONFIG_KMEMCHECK   

  73.     /* 

  74.      * kmemcheck wants to track the status of each byte in a page; this 

  75.      * is a pointer to such a status block. NULL if not tracked. 

  76.      */  

  77.     void *shadow;  

  78. #endif   

  79. };  
linux中主要的结构描述体现了linux物理内存管理的设计。后面会介绍linux内存管理的各个细节。见http://www.linuxidc.com/Linux/2012-01/50762.htm

赞(0) 打赏
转载请注明出处:服务器评测 » Linux物理内存描述
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏