良许Linux教程网 干货合集 Linux系统内核架构详解(一)

Linux系统内核架构详解(一)

Linux系统中内核是一个非常重要的一部分,那么Linux内核具体是什么样子呢?下面本篇文章和大家深入讲解一下Linux系统内核机构,有需要的朋友可以参考一下。

Linux系统内核架构详解(一)

1:在内核使用高端内存页之前,必须使用下文讨论的kmap和kunmap函数将其映射到内存虚拟地址空间中。

2:UMA计算机(一致内存访问,uniform memory access)将可用内存以连续方式组织起来。

3:NUMA计算机(非一致性内存访问,non-uniform memory access)系统的各个CPU都有本地内存,可支持特别快速的访问,各个处理器之间通过总线连接起来,以支持其他CPU的本地内存的访问。

img

4:内核会区分三种配置选项:FLATTMEM,DISCONTIGMEM,SPARSEMEM,DISCONTIGMEM.

img

5:内存划分为结 点。每个节点关联到系统中的一个处理器。在内核中表示为pg_data_t的实例。

6:各个结点又划分为 内存域,是内存域的进一步细分。

7:

img

注:zonelist:指向zonelist数据结构的指针,该数据结构按照优先次序描述了适于内存分配的内存管理区。

8:

img

1)ZONE_DMA标记适合DMA的内存域。

2)ZONE_DMA32标记了使用32位地址字可寻址,适合DMA的内存域。

3)ZONE_NORMAL标记了可直接映射到内核段的普通内存域,这是在所有体系结构上保证都会存在的唯一内存域,但无法保证该地址范围对应了实际的物理内存。

4)ZONE_HIGHMEM标记了超出内核段的物理内存。

5)伪内存域ZONE_MOVABLE.

6)MAX_NR_ZONES充当结束标志,在内核想要迭代系统中的所有内存域时,会用到该常量。

7)各个内存域都关联了一个数组,用来组织属于该内存域的物理内存页(页帧)。对每个页帧,都分配一个struct page实例以及所需的管理数据。

8)每个节点都提供了一个备用列表(借助struct zonelist)。该列表包含了其他节点(和相关的内存域),可用于代替当前节点分配内存。

3.2.2数据结构

1)结点管理

  pg_data_t用于表示节点的基本元素。

   typedef struct pglist_data{        struct zone node_zones[MAX_NR_ZONES];        struct zonelist node_zonelists[MAX_ZONELISTS];        int nr_zones;        struct page*node_mem_map;        struct bootmem_data *bdata;        unsigned long node_start_pfn;        unsigned long node_present_pages;/*物理内存页的总数*/        unsighed long node_spanned_pages;/*物理内存页的总数,包含洞在内*/                int node_id;        struct pglist_data *pgdat_next;        wait_queue_head_t kswapd_wait;        struct task_struct *ksward;        int ksward_max_order;}pg_data_t;

注:1)node_zones是一个数组,包含了节点中各内存域的数据结构。

   2)node_zonelists指定了备用节点及其内存域的列表,以便在当前节点没有可用空间时,在备用节点分配内存。

   3)节点中不同内存域的数目保存在nr_zones中

   4)node_mem_map是指向page实例数组的指针,用于描述节点的所有物理内存页,它包含了节点中所有内存域的页。

   5)bdata指向自举内存分配器数据结构的实例。

   6)node_start_pfn是该NUMA节点第一个页帧的逻辑编号。所有页帧是依次编号的,每个页帧的号码都是全局唯一的。

      在UMA中总是0.

   7)node_present_pages指定了节点中页帧的数目,node_spanned_pages则给出了该节点以页帧 为单位计算的长度。

   8)node_id是全局节点ID。

   9)pgdat_next连接到下一个内存节点,系统中所有的内存节点都通过单链表连接起来,其末尾通过空指针标记。

  10)kswapd_wait是交换守护进程(swap daemon)的等待队列,将在页帧换出节点时会用到。

      kswapd指向负责该节点的交换守护进程的task_struct.

      kswapd_max_order用于页交换子系统的实现,用来定义需要释放的区域的长度。

  11)节点的内存域保存在node_zones[MAX_NR_ZONES].该数组总是有3项。即使节点没有那么多内存域,若不足3个,则其余的数组项用0填充。

    enum node_states{     N_POSSIBLES,                   /*节点在某个时候可能变成联机*/     N_ONLINE,                      /*节点是联机的*/     N_NORMAL_MEMORY,               /*几点有普通内存域*/#ifdef CONFIG_HIGHMEM     N_HIGH_MEMORY,                 /*节点有普通或高端内存域*/#else     N_HIGH_MEMORY = N_NORMAL_MEMORY,#endif     N_CPU,                         /*节点有一个或者多个CPU*/     NR_NODE_STATES};

注:如果节点有普通或高端内存则使用N_HIGH_MEMORY,仅当节点没有高端内存才设置N_NORMAL_MEMORY.

2)内存域

内核使用zone结构来描述内存域。

  1. struct zone{

  2. /*通常由页分配器访问的字段*/

  3. unsigned long pages_min,pages_low,pages_high;        注:1)若空闲页的数目多于pages_high,则内存域的状态是理想的

  4. 2)若空闲页的数目低于pages_low,则内核开始将页换出到硬盘

  5. 3)若空闲页的数目低于pages_min,内存域急需空闲页,需页回收

  6. 4)数据结构中水印值得填充由init_per_zone_pages_min处理。

  7. 5)setup_per_zone_pages_min设置struct zone的pages_min,

  8. pages_low,pages_high成员。

  9. unsigned long lowmem_reserve[MAX_NR_ZONES];          注:该数组分别为各种内存域指定了若干项,用于一些无论如何都不能失败                                                             的关键性内存分配。

  10. struct per_cpu_pageset pageset[NR_CPUS];             注:该数组用于实现每个CPU的热/冷页帧列表。内核使用这些列表保存可                                                              用于满足实现的“新鲜”页。

  11. 热页帧:在高速缓存中,可以快速访问,

  12. 冷页帧:不在高速缓存中的页帧

  13. NR_CPUS是一个可以在编译时间配置的宏常数。

  14. 注:数组元素的类型为per_cpu_pageset

  15.         struct per_cpu_pageset{       struct per_cpu_pages pcp[2];/*索引0对应热页,索引1对应冷页*/}__cacheline_aligned_in_smp;

         注:该结构由一个带有数组项的数组构成,第一项管理热页。第二页管理冷页。

             有用的数据保存在per_cpu_pages中。

            struct per_cpu_pages{       int count;                     /*与该列表相关的页的数目*/       int high;                      /*high是页数上限水印,在需要的时候清空列表。若count的值超出high,即列表中的                                        页数太多*/       int batch;                     /*添加/删除多项页的时候,块的大小*/       struct list_head list;         /*list是页的双链表,保存当前CPU的冷页或者热页*/}

  1. /*

  2. *不同长度的空闲区域

  3. */

  4. spinlock_t           lock;

  5. struct free_area     free_area[MAX_OEDER];           注:是同名数据结构的数组,用于实现伙伴系统,每个数组元素都表示某种                                                             固定长度的一些连续的内存区。对于包含在每个区域中的空闲内存页                                                              的管理。free_area是一个起点。

  6. ZONE_PAGGING(_pad1_)

  7. /*通常由页面收回扫描程序访问的字段*/

  8. spinlock_t           lru_lock;

  9. struct list_head     active_list;                     注:是活动页的集合

  10. struct list_head     inactive_list;                   注:是不活动页的集合

  11. unsighed long        nr_scan_active;                  注:回收内存时需要扫描的活动页的数目

  12. unsighed long        nr_scan_inactive;                注:回收内存时需要扫描的不活动页的数目

  13. unsighed long        pages_scanned;                   注:上次回收以来扫描过的页

  14. unsighed long        flags;                          注:描述内存域当前状态

  15. 
    
            typedef  enum {         ZONE_ALL_UNERCLAIMABLE,         /*所有的页都已经钉住,不能回收*/         ZONE_RECLAIM_LOCKED,            /*防止并发回收*/         ZONE_OOM_LOCKED,                /*内存域即可被回收*/}zone_flags_t;
  16. /*内存域统计量*/

  17. atmoic_long_t        vm_stat[NR_VM_STAT_ITEMS];       注:维护了大量有关内存域的统计信息。辅助函数zone_page_state用来                                                              读取vm_stat中的信息

  18. int prev_priority;                                    注:存储了上一次扫描操作扫描该内存域的优先级。扫描操作是由try_to                                                              _free_pages进行的,直至释放了足够多的页帧。

  19. ZONE_PAGGING(_pad2_)

  20. /*很少使用或大多数情况下只读的字段*/

  21. wait_queue_head_t    *wait_table;                     注:是一个等待队列,可用于等待某一页变为可用进程。进程排成一个队   ``

  22. unsighed long        wait_table_hash_nr_entries;列,等待某些条件, 在条件为真时,内核会通知进程恢复工作。

  23. unsighed long        wait_table_bits;

  24. /*支持不连续内存模型的字段*/

  25. struct pglist_data  *zone_pgdat;                     注:内存域和父节点之间的关联由zone_pgdat建立,zone_pgdat指向对                                                               应的pg_list_data实例

  26. unsighed long       zone_start_pfn;                  注:内存域第一个页帧的索引

  27. unsighed long       spanned_pages;                       /*总长度,包括空洞*/

  28. unsighed long       present_pages;                       /*总长度,不包括空洞*/实际上可用的页数目

  29. /*

  30. *很少使用的字段

  31. */

  32. char               *name;                           注:是一个字符串,保存该内存域的惯用名称。3个选项可用,Normal,

  33. DMA,HighMem

  34. }__cacheline_maxaligned_in_smp;

3.内存域水印的计算

在计算水印之前,内核首先确定需要为关键性分配保留的内存空间的最小值。该值随可用内存的大小而非线性增长,并保留在全局变量min_free_kbytes中。

img

注:1)高端内存域的下界SWAP_CLUSTER_MAX.

   2)它定义了分组的大小。

   3)setup_per_zone_lowmem_reserve计算出lowmem_reserve

以上就是良许教程网为各位朋友分享的Linux系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你!

137e00002230ad9f26e78-265x300

本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部