(done) MIT6.S081 2023 学习笔记 (Day6: LAB5 COW Fork)

网页:https://pdos.csail.mit.edu/6.S081/2023/labs/cow.html


任务1:Implement copy-on-write fork(hard) (完成)

现实中的问题如下:
xv6中的fork()系统调用会将父进程的用户空间内存全部复制到子进程中。如果父进程很大,复制过程可能会花费很长时间。更糟糕的是,这项工作常常是大部分浪费的:在子进程中,fork()通常会被exec()紧随其后,exec()会丢弃复制的内存,通常这些内存大部分都没有被使用。另一方面,如果父子进程都使用了一个复制的页面,并且其中一个或两个进程对该页面进行了写操作,那么这个复制就是真正需要的。

解决方案:
实现写时复制(COW)fork()的目标是将物理内存页的分配和复制推迟到真正需要这些副本的时候,如果有的话。 COW fork()只为子进程创建一个页表,用户内存的PTE指向父进程的物理页面。COW fork()将父子进程中所有的用户PTE标记为只读。当任一进程尝试写入这些COW页面时,CPU将强制产生一个页错误。内核的页错误处理程序检测到这种情况,为出错进程分配一页物理内存,将原始页面复制到新页面,并修改出错进程中的相关PTE,使其指向新页面,这次将PTE标记为可写。当页错误处理程序返回时,用户进程将能够写入其页面的副本。

COW fork()使得释放实现用户内存的物理页面变得更加复杂。一个给定的物理页面可能被多个进程的页表引用,并且只有在最后一个引用消失时才应该被释放。在像xv6这样的简单内核中,这种簿记工作相对直接,但在生产内核中,这可能会很难做对;例如,参见《Patching until the COWs come home》(修补直到COW回家)。

根据讲义,这次的测试程序是 cowtest,在调用 fork 之前,用户程序会使用多余一半的内存。因此如果没有实现 COW fork,那么 cowtest 会失败

让我们看看 cowtest 源码:

int
main(int argc, char *argv[])
{simpletest();// check that the first simpletest() freed the physical memory.simpletest();threetest();threetest();threetest();filetest();printf("ALL COW TESTS PASSED\n");exit(0);
}

如上是 main 函数,大概过了一遍 simpletest, threetest, filetest 的源码。

测试内容是:
simpletest 检测 COW 是否节约了内存、是否能够释放内存
threetest 检测 COW 是否能够在子进程写入内存时分配新的页
filetest 检测读取这些内存时是否会出错,尤其是内核的 copyout 是否能和 COW 配合完美

我们直接跟着讲义和提示写代码吧:
1.Modify uvmcopy() to map the parent’s physical pages into the child, instead of allocating new pages. Clear PTE_W in the PTEs of both child and parent for pages that have PTE_W set. (设置为只读的目的是为了以后写入的时候能够触发 page fault;父子进程都要设置为 Read-only 是因为都需要触发 page-fault,当父进程对某块内存写入时,需要分配一个相应的内存页给子进程,否则子进程会访问到父进程写入的数据)
2. Modify usertrap() to recognize page faults. When a write page-fault occurs on a COW page that was originally writeable, allocate a new page with kalloc(), copy the old page to the new page, and install the new page in the PTE with PTE_W set. Pages that were originally read-only (not mapped PTE_W, like pages in the text segment) should remain read-only and shared between parent and child; a process that tries to write such a page should be killed. (COW 不能让本来只读的页面变成可写)
3. Ensure that each physical page is freed when the last PTE reference to it goes away – but not before. A good way to do this is to keep, for each physical page, a “reference count” of the number of user page tables that refer to that page. Set a page’s reference count to one when kalloc() allocates it. Increment a page’s reference count when fork causes a child to share the page, and decrement a page’s count each time any process drops the page from its page table. kfree() should only place a page back on the free list if its reference count is zero. It’s OK to to keep these counts in a fixed-size array of integers. You’ll have to work out a scheme for how to index the array and how to choose its size. For example, you could index the array with the page’s physical address divided by 4096, and give the array a number of elements equal to highest physical address of any page placed on the free list by kinit() in kalloc.c. Feel free to modify kalloc.c (e.g., kalloc() and kfree()) to maintain the reference counts.(当对于一个页面的所有引用都消失时,再释放这一页的内存)
4. Modify copyout() to use the same scheme as page faults when it encounters a COW page. (需要对 copyout 做一些修改)
5. It may be useful to have a way to record, for each PTE, whether it is a COW mapping. You can use the RSW (reserved for software) bits in the RISC-V PTE for this. (可以用 RSW bits 来记录一个 PTE 是否是一个 COW mapping)
6. Some helpful macros and definitions for page table flags are at the end of kernel/riscv.h. (kernel/riscv.h 里的内容可能有用)
7. If a COW page fault occurs and there’s no free memory, the process should be killed. (当发生 COW page fault 但没有足够内存时,进程应该被杀掉)

自己的提示:
在做 LAB3 : pagetable 的时候遇到过这么一张图,在这里也很有用
在这里插入图片描述
RSW bits 是 8~9

开始写代码:
1.在 vm.c : uvmcopy 添加 printf 打印 PTEs,发现 RSW bits 一直都是 0,说明平时不用都是置为 0
2.在 vm.c : uvmcopy 去掉分配内存和拷贝内存内容的部分,仅仅保留拷贝映射的部分。同时,设置老新页表的 RSW bits = original WR bits。此外,错误处理中去掉释放内存的部分,仅保留删除映射的部分。
3.在 trap.c : usertrap 中新添一个分支 “if scause == 0xf”。(0xd 是 load page fault,0xf 是 store page fault)使用 stval 寄存器的值作为触发 page fault 的页面起始地址va。使用 RSW bits 判断是否属于 COW pages,同时判断原来的权限。如果不属于 COW pages,直接 kill 掉;如果属于且本来可写,那么使用 kalloc 分配页面并设置为可写;如果属于 COW pages 但本来不可写,那么直接 kill 掉。如果使用 kalloc 由于内存不足失败,那么直接 kill 掉。这里注意使用 kalloc 分配页面成功时,修改 PTE 映射时要 clear RSW bits,否则以后该页被用户程序设置为只读时,发生 page-fault 会使用残留的 RSW bits 设置为可写。
4.在 kalloc.c 中维护一个全局的 reference_count 数组,大小为 [(PHYSTOP - KERNBASE) / PGSIZE]。在 kalloc 中,根据分配的页面的起始物理地址,把 reference_count 数组中对应元素设置为 1。把 mappages 包装出一个新的函数 uvmmap,替换掉原来调用 mappages 的地方。在 uvmcopy 中增加 reference_count 数组元素 (一个进程结束后,由于这个进程分配的页就应该回到 freelist,所以只考虑用户进程计算引用数,不考虑内核引用)。在 kfree 中减少 reference_count 数组元素,到 0 时真正释放内存(原因是,fork 后,多个程序会调用多次 kfree,所以在 kfree 中计数)。第一次调用 kfree (kinit) 的时候还没有调用过 kalloc,因此拷贝一个 kfree_initialize 来替换 kinit 中的 kfree
5.由于 copyout 会在内核态发生对 COW page 写入的操作,所以这里也要进行 page fault 的处理。如果发现是 COW page,为了不影响其它进程访问到的内存内容,我们调用 kalloc 申请一个新的页,然后拷贝原始内容,修改页表 … (跟 page fault 很相似)

出现内存泄漏的时候,可以使用 gdb watch 去观察 reference_count 数组的某些元素,找到修改这些元素的代码,这样能帮助我们快速调试。

出现内存泄漏的时候,调试思路为搞清楚几个问题:1.哪些内存地址没有被释放? 2.这些没被释放的内存地址是什么时候被分配的?3.它们为什么没有被释放?

一个很容易出错的地方:使用 fork 后,父子进程的 PTE 的 PTE_W 都要 clear,这是为了防止父进程对内存进行修改后,子进程访问到父进程修改的内容。那么此时有一个问题,父子进程都发生 store page fault 并且申请了新的 kalloc() 后,那么此时申请了两个新页,一开始的那个页就悬空泄露了,会造成内存泄漏。

个人感觉这次 LAB 最容易出 bug 的地方就是内存泄漏。

处理完后,运行 cowtest 很顺利如下:
在这里插入图片描述

再运行 usertests,发现报错,经过观察,发现只是对代码的修改导致代码在遇到错误情况时(比如内存不足或写入一个超高地址时应该返回 -1,或者直接把用户进程杀掉)没有返回正确的错误码,稍作调整即可。再次测试,顺利,如下:
在这里插入图片描述

所有 usertests 顺利通过

运行 make grade,所有测试顺利通过
在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/894115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸢尾花书01---基本介绍和Jupyterlab的上手

文章目录 1.致谢和推荐2.py和.ipynb区别3.Jupyterlab的上手3.1入口3.2页面展示3.3相关键介绍3.4代码的运行3.5重命名3.6latex和markdown说明 1.致谢和推荐 这个系列是关于一套书籍,结合了python和数学,机器学习等等相关的理论,总结的7本书籍…

【愚公系列】《循序渐进Vue.js 3.x前端开发实践》033-响应式编程的原理及在Vue中的应用

标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主&…

【javaweb项目idea版】蛋糕商城(可复用成其他商城项目)

该项目虽然是蛋糕商城项目,但是可以复用成其他商城项目或者购物车项目 想要源码的uu可点赞后私聊 技术栈 主要为:javawebservletmvcc3p0idea运行 功能模块 主要分为用户模块和后台管理员模块 具有商城购物的完整功能 基础模块 登录注册个人信息编辑…

为什么LabVIEW适合软硬件结合的项目?

LabVIEW是一种基于图形化编程的开发平台,广泛应用于软硬件结合的项目中。其强大的硬件接口支持、实时数据采集能力、并行处理能力和直观的用户界面,使得它成为工业控制、仪器仪表、自动化测试等领域中软硬件系统集成的理想选择。LabVIEW的设计哲学强调模…

Fort Firewall:全方位守护网络安全

Fort Firewall是一款专为 Windows 操作系统设计的开源防火墙工具,旨在为用户提供全面的网络安全保护。它基于 Windows 过滤平台(WFP),能够与系统无缝集成,确保高效的网络流量管理和安全防护。该软件支持实时监控网络流…

【PyTorch】6.张量形状操作:在深度学习的 “魔方” 里,玩转张量形状

目录 1. reshape 函数的用法 2. transpose 和 permute 函数的使用 4. squeeze 和 unsqueeze 函数的用法 5. 小节 个人主页:Icomi 专栏地址:PyTorch入门 在深度学习蓬勃发展的当下,PyTorch 是不可或缺的工具。它作为强大的深度学习框架&am…

[STM32 - 野火] - - - 固件库学习笔记 - - -十三.高级定时器

一、高级定时器简介 高级定时器的简介在前面一章已经介绍过,可以点击下面链接了解,在这里进行一些补充。 [STM32 - 野火] - - - 固件库学习笔记 - - -十二.基本定时器 1.1 功能简介 1、高级定时器可以向上/向下/两边计数,还独有一个重复计…

Cyber Security 101-Build Your Cyber Security Career-Security Principles(安全原则)

了解安全三元组以及常见的安全模型和原则。 任务1:介绍 安全已成为一个流行词;每家公司都想声称其产品或服务是安全的。但事实真的如此吗? 在我们开始讨论不同的安全原则之前,了解我们正在保护资产的对手至关重要。您是否试图阻止蹒跚学步…

python:斐索实验(Fizeau experiment)

斐索实验(Fizeau experiment)是在1851年由法国物理学家阿曼德斐索(Armand Fizeau)进行的一项重要实验,旨在测量光在移动介质中的传播速度。这项实验的结果对当时的物理理论产生了深远的影响,并且在后来的相…

青少年CTF练习平台 贪吃蛇

题目 CtrlU快捷键查看页面源代码 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>贪吃蛇游戏</title><style>#gameCanvas {border: 1px solid black;}</style> </head>…

芯片AI深度实战:基础篇之Ollama

有这么多大模型&#xff0c;怎么本地用&#xff1f; Ollama可以解决这一问题。不依赖GPU&#xff0c;也不需要编程。就可以在CPU上运行自己的大模型。 软件甚至不用安装&#xff0c;直接在ollama官网下载可执行文件即可。 现在最流行的deepseek-r1也可以使用。当然还有我认为最…

本地部署deepseek模型步骤

文章目录 0.deepseek简介1.安装ollama软件2.配置合适的deepseek模型3.安装chatbox可视化 0.deepseek简介 DeepSeek 是一家专注于人工智能技术研发的公司&#xff0c;致力于打造高性能、低成本的 AI 模型&#xff0c;其目标是让 AI 技术更加普惠&#xff0c;让更多人能够用上强…

DeepSeek R1中提到“知识蒸馏”到底是什么

在 DeepSeek-R1 中&#xff0c;知识蒸馏&#xff08;Knowledge Distillation&#xff09;是实现模型高效压缩与性能优化的核心技术之一。在DeepSeek的论文中&#xff0c;使用 DeepSeek-R1&#xff08;教师模型&#xff09;生成 800K 高质量训练样本&#xff0c;涵盖数学、编程、…

关联传播和 Python 和 Scikit-learn 实现

文章目录 一、说明二、什么是 Affinity Propagation。2.1 先说Affinity 传播的工作原理2.2 更多细节2.3 传播两种类型的消息2.4 计算责任和可用性的分数2.4.1 责任2.4.2 可用性分解2.4.3 更新分数&#xff1a;集群是如何形成的2.4.4 估计集群本身的数量。 三、亲和力传播的一些…

通过配置代理解决跨域问题(Vue+SpringBoot项目为例)

跨域问题&#xff1a; 是由浏览器的同源策略引起的&#xff0c;同源策略是一种安全策略&#xff0c;用于防止一个网站访问其他网站的数据。 同源是指协议、域名和端口号都相同。 跨域问题常常出现在前端项目中&#xff0c;当浏览器中的前端代码尝试从不同的域名、端口或协议…

(1)Linux高级命令简介

Linux高级命令简介 在安装好linux环境以后第一件事情就是去学习一些linux的基本指令&#xff0c;我在这里用的是CentOS7作演示。 首先在VirtualBox上装好Linux以后&#xff0c;启动我们的linux&#xff0c;输入账号密码以后学习第一个指令 简介 Linux高级命令简介ip addrtou…

TOGAF之架构标准规范-信息系统架构 | 数据架构

TOGAF是工业级的企业架构标准规范&#xff0c;信息系统架构阶段是由数据架构阶段以及应用架构阶段构成&#xff0c;本文主要描述信息系统架构阶段中的数据架构阶段。 如上所示&#xff0c;信息系统架构&#xff08;Information Systems Architectures&#xff09;在TOGAF标准规…

Windows 程序设计7:文件的创建、打开与关闭

文章目录 前言一、文件的创建与打开CreateFile1. 创建新的空白文件2. 打开已存在文件3. 打开一个文件时&#xff0c;如果文件存在则打开&#xff0c;如果文件不存在则新创建文件4.打开一个文件&#xff0c;如果文件存在则打开文件并清空内容&#xff0c;文件不存在则 新创建文件…

FastReport.NET控件篇之富文本控件

简介 FastReport.NET 提供了 RichText 控件&#xff0c;用于在报表中显示富文本内容。富文本控件支持多种文本格式&#xff08;如字体、颜色、段落、表格、图片等&#xff09;&#xff0c;非常适合需要复杂排版和格式化的场景。 富文本控件(RichText)使用场景不多&#xff0c…

爬虫基础(三)Session和Cookie讲解

目录 一、前备知识点 &#xff08;1&#xff09;静态网页 &#xff08;2&#xff09;动态网页 &#xff08;3&#xff09;无状态HTTP 二、Session和Cookie 三、Session 四、Cookie &#xff08;1&#xff09;维持过程 &#xff08;2&#xff09;结构 正式开始说 Sessi…