linux/mm/memory.c/free_page_tables()

2023-05-16

看linux0.11的源码有一段时间了,发现前期的轮廓建立起来后,重点马上到了具体操作上。即函数,毕竟OS本身是由一系列函数组成的,“源码面前了无秘密”,所以要深刻理解操作系统的神奇,深入理解每一个函数的每一行代码很是关键。
接下来一段时间,会随着学习的步骤,参看赵炯博士的内核注释和网上其他达人的点评注解,以每个函数为题目进行一个个人的注解。姑且厚颜算作原创吧,不为其他,只为记录下学习印记,加深印象而已。

今天是第一个函数,linux/mm/memory.c/free_page_tables()

/*
 * This function frees a continuos block of page tables, as needed
 * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
 */
int free_page_tables(unsigned long from,unsigned long size)
{
unsigned long *pg_table;
unsigned long * dir, nr;


// 这里的from是线性地址,需4MB对齐。因为free_page_tables函数用来释放一个页表的内存
// 而不是一个页面的内存。
if (from & 0x3fffff)
panic("free_page_tables called with wrong alignment");
if (!from)
panic("Trying to free up swapper memory space");
// size在计算前是字节为单位的需要释放的内存长度。而在右移22位并向上取整计算后则得到了
// 需要释放的内存页面的个数,即以4MB为单位的需要释放的内存页面个数。这里+0x3fffff是为了
// 向上取整,譬如4.01MB经过计算后也会得到2(4MB则刚好得到1)
size = (size + 0x3fffff) >> 22;
// dir意义为from地址对应的这个页表在页目录表中的表项首地址。(页目录表位于物理内存0x0000处,
// 占有1页内存,共有1K个页表项,每个页表项4字节。每个页表项的4字节作为一个指针又都指向
// 一个内存地址,这个地址就是一个页表的基地址。因此共有1K个页表,每个页表对应4M内存,因此
// linux0.11共支持4G的线性地址范围。这4G线性地址范围被64个进程瓜分,因此每个进程的独立
// 地址范围为4G/64 = 64M,这也就是每个进程最大线性地址的限制来历了。)
// 这里from为线性地址,因此可根据线性地址空间与页目录表中表项的对应关系来计算这个from
// 对应在哪个页表项中。from>>22即为对应的页表项号,但是每个页表项占4字节,因此要得到页表项
// 在页目录表内的首地址(注意区分页表项号与页表项号首地址),则要(from>>22)<<2 = from>>20
// & 0xffc是为了确保这个地址一定是页表项的首地址,而不会跑到4字节的中间某个字节去。实际上
// 在函数刚开始已经检验过from了,能执行到这里即说明from已经是4MB对齐了。但是linus还是执着
// 的进行了这个检测,可见linus编程风格之严谨。我能想到的这句代码的作用就是:在函数首部检验
// 代码和这句代码之间,若维护时不小心改变了from的值使其失去了4MB对齐的特性,这里又没检测
// 则会造成很大的崩溃。
dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
for ( ; size-->0 ; dir++) {
// dir为ulong型指针,占4个字节(即from对应的页目录表项首地址),指向一个ulong型数据,即
// 这个页目录表基地址。*dir即为这个页目录表项内容,也就是这个页目录表的基地址。此处检验
// 其最低位是不是1,查页目录表项结构即可知,最低位为P(Present,1表示这个表项可做映射,0
// 表示这个表项不可做映射),因此这个if是检验from要求释放的页表是不是有效页表。
if (!(1 & *dir))
continue;
// pg_table即为第一个要释放的页表的基地址指针,这里与0xfffff位与也是为了对齐验证
pg_table = (unsigned long *) (0xfffff000 & *dir);
// 找到了要释放的页表基地址,下面开始循环释放这个页表中1024个页面。调用free_page函数
// 实现释放一个物理页面。这里要注意free_page函数接收的addr为物理地址,而不是线性地址。
// 上面一直都在用线性地址,到了这里突然就成了物理地址,这里要注意的就是这个转折点了。
// 经过分析得知,从线性地址到物理地址的转折出现在从dir到*dir。也就是用线性地址得到dir,
// 然后*dir取出的却是物理地址,即页目录表中存的页表地址都是物理地址。整个地址转换系统中,
// 用户进程内的虚拟地址(逻辑地址)先经过段式转换到线性地址,然后页目录级使用线性地址,到了
// 页表级和页内都使用物理地址了。
// 这里也可以看出,一个进程初步建立时,至少要耗费2个page的主内存。第一个用来存task_struct
// 结构和内核栈;第二个即用来存该进程第一个页表。
// 这里我突然有个疑问:在这之后execve等耗费的内存可以由这个已经建立的页表来管理,那么这前两个
// 页面的内存由谁来管理呢?换句话说,这两个页面的物理内存由谁来释放呢?这里第一个页表所在page
// 的释放在下面就能找到答案,原来释free_page_tables函数中在释放完了一个页表中1024个页面后会
// 顺带释放这个页表本身占有的这个内存页面。而task_struct和内核栈共同占有的内存页的释放,
// 猜测只能由其父进程来代为释放了···具体如何,待继续寻找。
for (nr=0 ; nr<1024 ; nr++) {
if (1 & *pg_table)
// 调用free_page释放一个物理页面,释放的意思是在内核mem_map[]中对应该页
// 的项内数值减一。若减一后为0则代表该页内存成了空闲内存,若不为0则表示
// 该页内存还被别的进程引用,只是本进程对它的引用被释放断开了。
free_page(0xfffff000 & *pg_table);
// 页表中表项清零。因为这个表项指向的内存页面已经被释放了,与本进程无关了,因此
// 这里页表也再不用记录它了,直接清零即可。
*pg_table = 0;
pg_table++;
}
// 释放完第一个页表指向的1024个页面后,最后释放掉这个页表本身所在的那个页面。
free_page(0xfffff000 & *dir);
// 释放了页表所在页面,将该页表在页目录表中对应的页表项内容也清零
*dir = 0;
}
// 刷新页变换高速缓存,进入invalidate函数可知,这里是通过重新给CR3寄存器赋值来刷新的。
// 这里的页表换高速缓存是存在于CPU内部的,应该跟MMU有些关联。这一块暂时没搞明白···
// 现在能确定的是,free_page_tables是给exit函数调用的,因此是关闭进程时使用的。而关闭进程
// 必然导致CPU会访问的页面的变化,因此在这里进行了刷新
invalidate();
return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux/mm/memory.c/free_page_tables() 的相关文章

  • 配置 Visual Studio 以使用更多内存

    我曾经读过一篇关于如何增加 Visual Studio 将使用的 RAM 量的博客文章 当我尝试在 Visual Studio 编辑器中复制一小行文本时 收到 没有足够的可用内存 错误消息 有谁知道我可以如何或在哪里配置它 这是符合您的描述
  • 在单个命令中使用前缀重命名文件夹中的所有文件

    重命名带有前缀的文件夹中的所有文件 Unix 假设一个文件夹有两个文件 a txt b pdf 那么它们都应该从一个命令重命名为 Unix a txt Unix b pdf 如果您的文件名包含没有空格并且你没有任何子目录 你可以使用一个简单
  • Bash 中 $() 和 () 之间的区别

    当我打字时ls l echo file 支架的输出 这只是简单的回显 被获取并传递到外部ls l命令 就等于简单的ls l file 当我打字时ls l echo file 我们有错误 因为不能嵌套 内部外部命令 有人可以帮助我理解之间的区
  • 跟踪 pthread 调度

    我想做的是创建某种图表 详细说明 Linux 中 两个 线程的执行情况 我不需要查看线程的作用 只需查看它们何时被安排以及持续多长时间 基本上是一条时间线 在过去的几个小时里 我一直在互联网上搜索跟踪 pthread 调度的方法 不幸的是
  • 如何删除树莓派的相机预览

    我在我的 raspberryPi 上安装了 SimpleCv 并安装了用于使用相机板的驱动程序 uv4l 驱动程序 现在我想使用它 当我在 simpleCV shell Camera 0 getImage save foo jpg 上键入时
  • 对 sf:: 的未定义引用

    我想用 C 制作 GUI 应用程序 发现 SFML 是一个不错的选择 幸运的是 我使用的是 Linux 所以 SFML 2 4 已经安装在我的系统上 所以我开始搜索一些教程并找到了一个制作简单窗口的教程 但是当我运行代码时 出现错误 提示未
  • xdotool 类型需要很长时间并导致整个桌面冻结

    我一直在使用xdotool type过去只能在快捷方式上输入耸肩xdotool type 这可行 但总是需要相当长的时间 并导致整个桌面冻结 完全冻结 而不仅仅是输入 几秒钟 不过并没有太打扰我 现在我需要一种方法来从文件中读取内容 对其进
  • 使用 sed 将 old-link-url 替换为 new-link-url

    我正在 bash 中编写一个脚本 将 old link url 替换为 new link url 我的问题是 sed 由于斜杠而无法替换 url 如果我只输入一些文字就可以了 my code sed e s old link new lin
  • Docker DNS 设置

    我尝试使用自定义网络和 dos 设置创建 docker 容器 docker网络创建 driver bridge opt com docker network bridge enable ip masquerade true opt com
  • gnome-terminal 新选项卡,使用别名作为要执行的命令

    我已经创建了一个别名 bashrc文件如下 alias myproject cd Desktop myproject 当我重新启动终端时保存文件后 输入myproject带我到项目目录 但是当我尝试使用别名作为新的命令参数时gnome te
  • WPF 窗口关闭后不会释放内存

    我创建了一个测试代码 private void Application Startup 1 object sender StartupEventArgs e ShutdownMode System Windows ShutdownMode
  • 远程linux服务器到远程linux服务器大型稀疏文件复制 - 如何?

    我有两台 CentOS 5 4 服务器 每台服务器上都安装了 VMware Server 假设我始终对 vmware 虚拟机使用稀疏文件 将虚拟机文件从一台服务器复制到另一台服务器的最可靠 最快速的方法是什么 虚拟机的文件复制起来很痛苦 因
  • gcc 不太可能使用宏

    我正在编写一段关键代码 其逻辑大致如下 if expression is true do something with extremely low latency before the nuke blows up This branch i
  • grails 上的同步块在 Windows 上有效,但在 Linux 上无效

    我有一个 grails 应用程序 它依赖于服务中的同步块 当我在 Windows 上运行它时 同步按预期工作 但当我在 ams linux 上运行时 会出现 StaleObjectStateException 该问题在以下示例中重现 cla
  • Windows 与 Linux 文本文件读取

    问题是 我最近从 Windows 切换到 Ubuntu 我的一些用于分析数据文件的 python 脚本给了我错误 我不确定如何正确解决 我当前仪器的数据文件输出如下 Header 有关仪器等的各种信息 Data 状态 代码 温度 字段等 0
  • 是否有可能在linux中找到包含特定文本的文件?

    考虑这种情况 我在文件夹 Example 下有很多文件 如果我需要找到一个包含特定短语 如 Class Example 的文件 我该如何使用 Linux shell 来做到这一点 linux中有类似 定位 的函数可以做到这一点吗 Thank
  • 强制jvm返回本机内存[重复]

    这个问题在这里已经有答案了 我时不时地运行需要大量内存的 eclipse 任务 因此 当任务运行时 jvm 会消耗大约 2 3GB 的 RAM 这是可以的 但是一旦 jvm 占用了该内存 它就不会释放它 并且我遇到了一种情况 堆中已用内存约
  • Codeigniter 处理大文件时允许的内存大小耗尽

    我发布此内容是为了防止其他人正在寻找相同的解决方案 因为我刚刚在这个废话上浪费了两天时间 我有一个 cron 作业 每天使用一个非常大的文件更新数据库一次 使用以下代码 if handle fopen dirname FILE uncomp
  • 序列化对于对象大小估计可靠吗?

    我使用序列化来估计对象使用的内存量 我已经读过this https stackoverflow com questions 426396 how much memory does a c net object use and this ht
  • OpenCL 何时使用全局、私有、本地、常量地址空间

    我正在尝试学习 OpenCL 但我很难决定使用哪些地址空间 因为我只找到组装的资源声明这些地址空间是什么 但没有声明它们为什么存在或何时使用它们 资源至少太分散了 所以带着这个问题我希望把所有这些信息汇总一下 所有地址空间是什么 它们为什么

随机推荐