最近转载了不少文章,自己也读了ULK3 MM章节数遍,小有体会。写一些心得,以免自己忘记。

之前一些virtual address到physical address的映射的基本MM机制,可以参看博客转载的其他文章,不再一一赘叙。本文打算主要focus在源码和一些细节的理解上。另外提一句,我看的kernel版本是2.4.0

在描述之前要对两个看起来很简单的基本概念进行澄清,其实不是看起来那么简单。page and page frame。

根据ULK3 P.50描述,线性地址被分成以固定长度为单位的组,称为page。说明page是一个线性地址,也就是Linux中的虚拟地址的概念。而且page既指一组线性地址(4KB),又包括在这组地址中的数据。(我目前的理解)但是在函数alloc_pages()中的返回值struct page*为一个物理地址的指针。我们可以用void* page_address(struct page *page)将其转化为逻辑地址。(这个意义上说page又是指物理地址...)

而page frame是指分页单元把所有RAM分成固定长度的frame,每个page frame包括一个page。这是一个physical memory的概念。

现在我们考虑NUMA。Linux 把物理内存划分为3个层次来管理:存储节点(Node)、管理区(Zone)和页面(Page),并用3 个相应的数据结构来描述。为什么这样划分,后面会讲到。

先看看整体的结构:

all_mem

/     |       \

/   |        \

pglist_data   pglist_data  pglist_data

/  |   \

/      |       \

zone_dma zone_normal zone_high

|

page

|

page

整个memory分成不同的pglist_data,每个pglist_data代表一个Node,每个Node又分为三个zone,分别是ZONE_DMA, ZONE_NORMAL, ZONE_HIGHMEM。每个zone里面由若干个page组成。

我们结合代码看一下这几个结构声明。

1)Page

先说说我们比较熟悉的page,对一个page的描述在文件 include/linux/mm.h struct page中。贴过来看一下。

typedef struct page {

struct list_head list;

struct address_space *mapping;

unsigned long index;

struct page *next_hash;

atomic_t count;

unsigned long flags;/* atomic flags, some possibly updated asynchronously */

struct list_head lru;

unsigned long age;

wait_queue_head_t wait;

struct page **pprev_hash;

struct buffer_head * buffers;

void *virtual; /* non-NULL if kmapped */

struct zone_struct *zone;

} mem_map_t;

系统在每个物理页面都有一个page结构,根据陈莉君教授在kernel宝典中的描述,初始化时候会根据内存大小建立一个page结构的数组mem_page。

2) Node

这个地方就和NUMA有关系了。因为不同的内存经过不同的总线被访问到,或者一些类似的原因,使得CPU对不同内存单元的访问时间不一样。因此Kernel把所有物理内存分为几个Node,每个Node中,可以理解成是由同一种介质的内存组成,所以相同CPU访问页面所需要的时间相同。(我个人猜想如果有其他的内存插在另外一台通过系统总线连接的服务器上,这样Kernel就会相应分成两个Node的意思吧。)一般我们在一台PC机上不需要考虑多个Node的问题,都是UMA,也就是只有一个Node。

Node的数据结构为pglist_data,描述于include/linux/mmzone.h 中:

typedef struct pglist_data {

zone_t node_zones[MAX_NR_ZONES];

zonelist_t node_zonelists[NR_GFPINDEX];

struct page *node_mem_map;

unsigned long *valid_addr_bitmap;

struct bootmem_data *bdata;

unsigned long node_start_paddr;

unsigned long node_start_mapnr;

unsigned long node_size;

int node_id;

struct pglist_data *node_next;

} pg_data_t;

extern int numnodes;

extern pg_data_t *pgdat_list;

若干存储节点的pglist_data 数据结构可以通过node_next 形成一个单链表队列。

每个结构中的node_mem_map 指向具体节点的page 结构数组,而数组node_zone[]就是该节点的最多3 个页面管理区。

3) Zone

Linux 又把物理页面划分为3个区:

• 专供DMA 使用的ZONE_DMA 区(小于16MB);

• 常规的ZONE_NORMAL 区(大于16MB 小于896MB);

• 内核不能直接映射的区ZONE_HIGMEM 区(大于896MB)。

每个zone都用struct zone_struct 结构来表示, 描述于include/linux/mmzone.h:

typedef struct zone_struct {

/*

* Commonly accessed fields:

*/

spinlock_tlock;

unsigned longoffset;

unsigned longfree_pages;

unsigned longinactive_clean_pages;

unsigned longinactive_dirty_pages;

unsigned longpages_min, pages_low, pages_high;

/*

* free areas of different sizes

*/

struct list_headinactive_clean_list;

free_area_tfree_area[MAX_ORDER];

/*

* rarely used fields:

*/

char*name;

unsigned longsize;

/*

* Discontig memory support fields.

*/

struct pglist_data*zone_pgdat;

unsigned longzone_start_paddr;

unsigned longzone_start_mapnr;

struct page*zone_mem_map;

} zone_t;

对struct zone_struct结构中每个域的描述如下:

lock :用来保证对该结构中其它域的串行访问

free_pages :在这个区中现有空闲页的个数

pages_min、pages_low及 pages_high是对这个区最少、此少及最多页面个数的描述

need_balance:与kswapd合在一起使用

free_area:在伙伴分配系统中的位图数组和页面链表

zone_pgdat:本管理区所在的存储节点

zone_mem_map:该管理区的内存映射表

zone_start_paddr:该管理区的起始物理地址

zone_start_mapnr:在mem_map中的索引(或下标)

name:该管理区的名字

size:该管理区物理内存总的大小

其中,free_area_t定义为:

#difine   MAX_ORDER  10

type struct free_area_struct {

struct list_head   free_list

unsigned  int    *map

} free_area_t

zone_struct结构中的free_area[MAX_ORDER]是一组“空闲区间”链表。为什么要定义一组而不是一个空闲队列呢?这是因为常常需要成块地在物理空间分配连续的多个页面,所以要按块的大小分别加以管理。因此,在管理区数据结构中既要有一个队列来保持一些离散(连续长度为1)的物理页面,还要有一个队列来保持一些连续长度为2的页面块以及连续长度为4、8、16、…、直至2^MAX_ORDER(即4M字节)的队列。

linux源代码解读,【原创】Linux MM 源代码解读 (1)相关推荐

  1. linux第三方串口,[原创]Linux下的第三方登录认证实现

    本文的动机来自于一个项目,即:实现linux下的刷卡登录系统.因为使用ubuntu的缘故,接到项目时的第一感觉就是改写GDM.在GDM代码差不多看完以后,发现GDM认证采用了PAM机制.这种将认证交由 ...

  2. linux教程 nfs,[原创]linux视频教程之NFS

    这次主要说一下NFS /etc/exports:这个文件就是 NFS 的配置设定档  如果没有就自己创建一个 /var/lib/nfs/xtab:这个文件则是主要的 NFS 的纪录文件!当我们的 NF ...

  3. 手机和Linux蓝牙通信,[原创]linux下手机与蓝牙的连接配置

    代码: 全选# # HCI daemon configuration file. # # HCId options options { # Automatically initialize new d ...

  4. linux查看文件夹个球,[原创]linux下面的打小球游戏

    [原创]linux下面的打小球游戏 (2012-04-10 04:51:44) 标签: linux 游戏 杂谈 [原创]linux下面的打小球游戏linux下面的C编程,我还是新手,请大家别笑话. # ...

  5. 复制linux内核,linux内核写时复制机制源代码解读

    作者简介 写时复制技术(一下简称COW)是linux内核比较重要的一种机制,我们都知道:父进程fork子进程的时候,子进程会和父进程会以只读的方式共享所有私有的可写页,当有一方将要写的时候会发生COW ...

  6. linux内核奇遇记之md源代码解读之八阵列同步二

    linux内核奇遇记之md源代码解读之八阵列同步二 转载请注明出处:http://blog.csdn.net/liumangxiong 在上一小节里讲到启动同步线程: 7824 mddev->s ...

  7. linux内核奇遇记之md源代码解读之十二raid读写

    linux内核奇遇记之md源代码解读之十二raid读写 转载请注明出处:http://blog.csdn.net/liumangxiong 我们都知道,对一个linux块设备来说,都有一个对应的请求队 ...

  8. git 的安装以及使用:是一个开源的分布式版本控制系统,可以对项目进行版本管理。 早期是linux之父用来管理linux系统源代码的(linux是和windows一样操作系统 开源免费的操作...

    ## 总结 - 学会使用基本的git命令 管理源代码 - 学会去github创建仓库 并将代码上传到github的仓库 (有待完成 回家有网再push) - 了解本地的.git和服务器github的. ...

  9. arm linux head.s,arm-linux head.S 源代码分析

    arm-linux head.S 源代码分析 arm-linux head.S 源代码分析 这是ARM-Linux运行的第一个文件,这些代码是一个比较独立的代码包裹器.其作用就是解压Linux内核,并 ...

  10. windows 打包 python 然后linux执行_使用pyinstaller打包python源代码,成为linux/windows下可执行文件...

    pyinstaller,打包python源代码,成为linux/windows下可执行文件,多平台 下载:http://www.pyinstaller.org/static/ http://www.p ...

最新文章

  1. 阅读豆丁网----基于模型的混合多目标算法的研究
  2. 离线轻量级大数据平台Spark之MLib机器学习库线性回归实例
  3. FastJson、Jackson、Gson进行Java对象转换Json的细节处理
  4. 关于PostMessage后台发送组合键
  5. Exception in thread main org.apache.thrift.transport.TTransportException: Could not create ServerS
  6. nio2和nio2_列出和过滤NIO.2中的目录内容
  7. 有一个长为n的数组A,求满足0≤a≤bn的A[b]-A[a]的最大值。 给定数组A及它的大小n,请返回最大差值。...
  8. 三分法解决凸(凹)函数极值问题
  9. wechat-app-mall — 微信小程序商城,微信小程序微店
  10. Django面试题(一)django的中间件最多可以写几个方法?使用中间件做什么?
  11. windows 计算机 快捷键,Windows7计算器快捷键汇总
  12. c command语言学例子,语言学资料(一)CHAPTER 4
  13. matlab 折射率椭球,折射率椭球详解.ppt
  14. Extention匿名类
  15. Android 按钮实现按压水波纹效果
  16. 好评率超高的9个公众号,值得收藏
  17. 直通转发(cut-through)和存储转发(store-and-forward)的区别
  18. 初步理解为什么要用持久层,持久层使用数据库高效的原因
  19. 航班管家和连咖啡:连长的场景战术
  20. Python3 Hovercraft创建impressive.js演示文档(二)

热门文章

  1. python随机生成模块的应用
  2. python文件操作,r w a系列
  3. Python使用正则表达式分割字符串
  4. 线程阻塞的概念 (Java 中的睡眠状态sleep 等待状态wait 礼让状态yield 自闭状态join suspend() 和 resume() )
  5. Opencv 深度学习中为什么普遍使用BGR而不用RGB?
  6. 运行 YunYang1994/tensorflow-yolov3 所遇到的一些问题记录
  7. python 如何理解SVM(支持向量机)? 还有SVC.decision_function( )功能
  8. Zeal工具下载Elasticsearch离线文档
  9. brew 安装mysql5.6_mac使用brew安装mysql的坑
  10. SpringMVC学习(六)——Spring四种方式整合MyBatis