Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1071492
  • 博文数量: 277
  • 博客积分: 8313
  • 博客等级: 中将
  • 技术积分: 2976
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-22 11:25
文章分类

全部博文(277)

文章存档

2013年(17)

2012年(66)

2011年(104)

2010年(90)

我的朋友

分类: LINUX

2012-05-14 10:00:05

linux使用于广泛的体系结构,因此需要用一种与体系结构无关的方式来描述内存。linuxVM描述和管理内存。在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上运行,因此从当前节点得到的内存很可能被用到。

[cpp] view plaincopyprint?

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_pfnnode_present_pagesnode_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结构体描述,对于管理区的类型描述如下

[cpp] view plaincopyprint?

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.      };  

里面的英文注释已经写的很详细了。

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

[cpp] view plaincopyprint?

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内存区域中无法分配到内存时,需要从normalDMA区域中分配内存。 

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用于记录该页面的状态。

[cpp] view plaincopyprint?

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内存管理的各个细节。

 

阅读(1183) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~