diff --git "a/1.Linux\345\256\211\350\243\205\344\270\216\350\256\277\351\227\256/record/HelloWorld" "b/1.Linux\345\256\211\350\243\205\344\270\216\350\256\277\351\227\256/record/HelloWorld" old mode 100755 new mode 100644 diff --git "a/1.Linux\345\256\211\350\243\205\344\270\216\350\256\277\351\227\256/note.md" "b/1.Linux\345\256\211\350\243\205\344\270\216\350\256\277\351\227\256/report.md" similarity index 58% rename from "1.Linux\345\256\211\350\243\205\344\270\216\350\256\277\351\227\256/note.md" rename to "1.Linux\345\256\211\350\243\205\344\270\216\350\256\277\351\227\256/report.md" index 2085b37e5582a405c98e2afa1abb252185a9cb34..a4cc0325e9dc7ec393c31984dbbff0a59499869b 100644 --- "a/1.Linux\345\256\211\350\243\205\344\270\216\350\256\277\351\227\256/note.md" +++ "b/1.Linux\345\256\211\350\243\205\344\270\216\350\256\277\351\227\256/report.md" @@ -1,7 +1,7 @@ -# Linux修改时区的正确方法 -ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -# centOS 7 gcc install -yum install gcc -y -# 编译和运行HelloWorld -gcc HelloWorld.c -o HelloWorld-getchar -HelloWorld-getchar +## Linux修改时区的正确方法 +ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +## centOS 7 gcc install +yum install gcc -y +## 编译和运行HelloWorld +gcc HelloWorld.c -o HelloWorld-getchar +HelloWorld-getchar diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/1_topology_1" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/1_topology_1" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/1_topology_2" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/1_topology_2" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/1_topology_3" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/1_topology_3" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/3_pthread" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/3_pthread" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/Mycshell" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/code/Mycshell" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/pic/1_topology_1.png" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/pic/1_topology_1.png" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/pic/1_topology_3.png" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/homework/pic/1_topology_3.png" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/daemon-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/daemon-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/fork-100-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/fork-100-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/fork-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/fork-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/fork-exec-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/fork-exec-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/fork-twice-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/fork-twice-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/orphan-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/orphan-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/pthread-100-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/pthread-100-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/pthread-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/pthread-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/shell-script" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/shell-script" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/zombie-demo" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/code/zombie-demo" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-2 \345\261\217\346\230\276 HelloWorld \345\217\257\346\211\247\350\241\214\346\226\207\344\273\266\344\277\241\346\201\257.png" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-2 \345\261\217\346\230\276 HelloWorld \345\217\257\346\211\247\350\241\214\346\226\207\344\273\266\344\277\241\346\201\257.png" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-3 pstree \350\276\223\345\207\272.png" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-3 pstree \350\276\223\345\207\272.png" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-4 \346\237\245\347\234\213\344\274\232\350\257\235\343\200\201\350\277\233\347\250\213\347\273\204\345\222\214\346\216\247\345\210\266\347\273\210\347\253\257\347\232\204\344\276\213\345\255\220.png" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-4 \346\237\245\347\234\213\344\274\232\350\257\235\343\200\201\350\277\233\347\250\213\347\273\204\345\222\214\346\216\247\345\210\266\347\273\210\347\253\257\347\232\204\344\276\213\345\255\220.png" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-5 shell-script \350\204\232\346\234\254\347\232\204\346\211\247\350\241\214.png" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-5 shell-script \350\204\232\346\234\254\347\232\204\346\211\247\350\241\214.png" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-7 fork-demo \347\232\204\350\276\223\345\207\272.png" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/record/pic/2-7 fork-demo \347\232\204\350\276\223\345\207\272.png" old mode 100755 new mode 100644 diff --git "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/note.md" "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/report.md" similarity index 91% rename from "2.\350\277\233\347\250\213\346\216\247\345\210\266/note.md" rename to "2.\350\277\233\347\250\213\346\216\247\345\210\266/report.md" index 3efb0a44a08663b7941d55dd9679c8e44ce0b5e1..05d29cb5c8c290cf4c0bcad6c0a2db0f5e7e509a 100644 --- "a/2.\350\277\233\347\250\213\346\216\247\345\210\266/note.md" +++ "b/2.\350\277\233\347\250\213\346\216\247\345\210\266/report.md" @@ -1,146 +1,158 @@ -# 实验记录 -### 2-1 察看HelloWorld-gechar 的三个进程
-```bash -ps -aux | grep HelloWorld -``` -3个进程的PID分别是26608 26649 26689
-![image](./record/pic/2-1.jpg) - -### 2-2 屏显 HelloWorld 可执行文件信息
-```bash -file HelloWorld -``` -![image](./record/pic/2-2.png) -x86-64 平台上的ELF 格式可执行文件。 -一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件。 -ELF文件由4部分组成,分别是ELF头(ELF header)、程序头表(Program header table)、节(Section)和节头表(Section header table)。 -由于ELF 文件内部包含了足够的信息,操作系统可以根据ELF 可执行文件创建出进程映像,进程映像以及各种管理数据结构构成了进程实体,另外进程还可能向系统申请各种资源——共同组成了进程实体的全部内涵。进程实体被调度运行就构成了进程的活动,如果系统中有多个活动的进程,那么它们各自有独立的进程空间(各自独立地使用自己的0~0xFFFFFFFF 虚存空间)。
-在Linux 中进程PCB 是task_struct 结构体,
- -### 进程间组织关系
-Linux 系统中所有进程通过进程控制块PCB(struct task_struct)形成多种组织关系。根据 -进程创建过程可以有亲缘关系,通过进程间的父子关系组织成一个进程树
-一个进程通过创建一个子进程则形成父子关系,如果创建多个子进程,那么这些新创建的 -进程间属于兄弟关系
-### 2-3 pstree 输出 -![image](./record/pic/2-3.png) -### 2-4 查看会话、进程组和控制终端的例子 -![image](./record/pic/2-4.png) -### PPID(PPID,Parent PID) PID(进程ID) PGID(Process Group ID 进程组 ID号) SID(Session ID 会话ID) TTY TPGID(tty process group ID for the process group leader) STAT() UID TIME COMMAND
-STAT:D 无法中断的休眠状态(通常 IO 的进程);R 正在运行可中在队列中可过行的;S 处于休眠状态;T 停止或被追踪;W 进入内存交换(从内核2.6开始无效);X 死掉的进程(从来没见过);Z 僵尸进程;+ 位于后台的进程组
-“会话/进程组/线程组”几个概念呈现层级关系,Linux 系统中可以有多个会话(session), -每个会话可以包含多个进程组(process group),每个进程组可以包含多个进程,每个进程构 -成一个线程组——一个线程组由一个进程内的一个或多个线程组成,这些对象都有各自的ID。会话是从用户登录系统到退出前的全部活动,不同帐户的登录属于不同会话,而同一帐户的多次登录也构成不同的会话。而进程组主要出于作业控制的目的,有些shell 没有作用控制能力,就将整个会话的所有进程构成一个进程组。 -### 2-5 创建进程的命令 -```bash -chmod a+x shell-script -shell-script -``` -![image](./record/pic/2-5.png) -第一行用于指出该脚本需要用/usr/bin/bash 来解 -释执行,第二行shell 内部命令echo 用来显示,第三行HelloWorld 是外部命令(磁盘上的可执 -行文件)。 -### 2-6 通过ps 查找进程的PID -1.查找进程的PID
-2.kill PID
-```bash -ps -ef | grep HelloWorld-getchar -``` -![image](./record/pic/2-6.png) -### 2-7 fork-demo 的输出 -![image](./record/pic/2-7.png) -fork 函数被成功调用后将按照父进程的样子复制出一个完全相同的子进程。父进程fork() -函数结束时的返回值是子进程的PID 编号。新创建的子进程则也是从fork()返回处开始执行, -但不同的是它获得的返回值是0。也就是说父子进程执行上几乎相同,
-* 唯一区别是子进程中返回0 值而父进程中返回子进程PID。
-* 如果fork()出错则只有父进程获得返回值-1 而子进程未能创建。
-### 2-8 fork-demo 的输出 -![image](./record/pic/2-8.png) -### 2-9 fork-twice-demo 执行后的 输出 -![image](./record/pic/2-9.png) -### 孤儿进程和僵尸进程 -(1) 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init 进程(进程号为1)所收养,并由init 进程对它们完成状态收集工作。 -(2) 僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。 - 子进程结束后大部分资源都将直接回收,但是还将在PCB(struct task_struct 和内核堆栈)中记录一些退出时的状态等信息,这些信息供父进程检查后才能销毁回收。因此,僵尸进程因相应的数据没有父进程处理并回收,将会导致资源浪费,而孤儿则不会有这样的问题。 -* 孤儿进程 -![image](./record/pic/孤儿进程.png) -* 僵尸进程 -![image](./record/pic/僵尸进程.png) -### 2-10 fork-exec-demo 的执行结果 -![image](./record/pic/2-10.png) -* 这里可以看到子进程通过execve()将自己变身为“/usr/bin/ls”,因此不再执行与父进程里的代——即后面的“printf("this printf()will not be executed, because …”是没有机会得到执行的。 -* fork()和exec 函数族构成了创建新进程的完整操作,如果父子进程功能相同则只用fork(),如果父子进程不同则利用exec 函数族的来实现。 -### 2-11 用ps –ajx 查看daemon-demo 守护进程 -![image](./record/pic/2-11.png) -关闭daemon-demo运行终端后仍能找到daemon-demo进程,且PID为1 -### 2-12 /etc/rsyslog.conf 中的内容 -![image](./record/pic/2-12.png) -日志信息写入了/var/log/messages 文件中。 -### 2-13 查看/var/log/messages -![image](./record/pic/2-13.png) -由于前后运行了多次,所以出现了3个。 -### 2-14&2-15 pthread-demo 的输出及ps –aLf 的输出 -![image](./record/pic/2-14&2-15.png) -两个线程公用一个PID号19392,但是LWP却不一样。 - -### 2-16&2-17 PCB 开销 -```bash -cat /proc/slabinfo | grep task_struct -``` -比较两者在进程控制块上的开销(包括 struct task_struct 和内核栈) -2-16 fork-100-demo 运行前后的/proc/slabinfo 中关于 task_struct 数量 -![image](./record/pic/2-16.png) -2-17 pthread-100-demo 运行前后的/proc/slabinfo 中关于 task_struct 数量 -![image](./record/pic/2-17.png) -两者在运行后的task_struct数量均增加100,说明线程作为调度执行单位,进程控制块PCB(task_struct)还是需要的,这是最小资源的一部分。因此这方面资源开销对进程和线程都是一样的。 -### 2-18&2-19&2-20&2-21内存描述符开销 -* 查看mm_struct数量 -```bash -cat /proc/slabinfo | grep mm_struct -``` -2-18 fork-100-demo 运行前后的/proc/slabinfo 中关于 mm_struct 数量 -![image](./record/pic/2-18.png) -2-19 pthread-100-demo 运行前后的/proc/slabinfo 中关于 mm_struct 数量 -![image](./record/pic/2-19.png) -前者运行时mm_struct数量增加了100,而后者没有变化,说明,pthread-100-demo 虽然创建了 100 个线程,但是用于共享进程空间,并没有增加一个 mm_struct -* 查看vm_area_struct数量 -```bash -cat /proc/slabinfo | grep vm_area_struct -``` -2-20 fork-100-demo 运行前后的/proc/slabinfo 中关于 vm_area_struct 数量 -![image](./record/pic/2-20.png) -2-21 pthread-100-demo 运行前后的/proc/slabinfo 中关于 vm_area_struct 数量 -![image](./record/pic/2-21.png) -可以发现pthread-100-demo需要新增大约 150 左右的使用量,而fork-100-demo需要约 1300 左右的使用量,故线程的开销确实比进程要小。 - -# 课后作业 -### 1.编写 C 语言程序,利用 fork()创建子进程,形成以下父子关系:并通过 ps 命令检查进程的进程号 PID 和父进程号 PPID 证明你成功创建相应的父子关系,同时也用 pstree 输出进程树结构来验证其关系。 -![image](./homework/pic/problem_1.png) -* 解答: -* (1).[code](./homework/code/1_topology_1.c) - ![image](./homework/pic/1_topology_1.png) -可以看到父进程12232拥有10个子进程且满足题目的要求 -* (2).[code](./homework/code/1_topology_2.c) - ![image](./homework/pic/1_topology_2.png) -可以看到父进程13738拥有10个子进程且满足题目的要求 -* (3).[code](./homework/code/1_topology_3.c) - ![image](./homework/pic/1_topology_3.png) -可以看子进程结构满足题目要求。 -### 3.创建多个线程,在各个线程中打印出堆栈变量的地址,大致标记出其位置,注意区分主线程的堆栈和其他线程堆栈位置的差异。 -* 解答:[code](./homework/code/3_pthread.c) -注意:编译时需要链接文件-lpthread -rdynamic -```bash -gcc ./3_pthread.c -lpthread -rdynamic -o 3_pthread -``` - ![image](./homework/pic/3_pthread.png) - 程序中有一个父线程以及3个子线程,可以发现子线程的偏移地址以及返回地址都是一样的,且斗与父线程不一样。 - - ### 4.尝试自行设计一个 C 语言小程序,完成最基本的 shell 角色:给出命令行提示符、能够接受命令;对于命令分成三种,内部命令(例如 help 命令、exit 命令等)、外部命令(常见的 ls、cp 等,以及其他磁盘上的可执行程序 HelloWrold 等)以及无效命令(不是上述两种命令)。 - * 解答:[code](./homework/code/shell.c) -![image](./homework/pic/4_shell.png) - -捕获键盘输入->判断是那种命令-> -* 1.内部命令:打印help文件或exit(0);退出
-* 2.外部命令,fork出新的进程并使用execvp函数执行 -* 3.可执行程序,与外部命令方法相同 -* 4.无效命令:打印无效警告 +[toc] +## 实验目的 +* 通过编程实践、观察,学习内存管理的方式。 +## 实验环境 +* 硬件 +1.Intel(R) Xeon(R) Bronze 3104 CPU @ 1.70GHz +2.DDR4 16G +* 软件 +1.CentOS 7 +2.ubuntu 18.04 +3.VMware Workstation Pro 15 +## 实验记录 +### 2-1 察看HelloWorld-gechar 的三个进程
+```bash +ps -aux | grep HelloWorld +``` +3个进程的PID分别是26608 26649 26689
+![image](./record/pic/2-1.jpg) + +### 2-2 屏显 HelloWorld 可执行文件信息
+```bash +file HelloWorld +``` +![image](./record/pic/2-2.png) +x86-64 平台上的ELF 格式可执行文件。 +一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件。 +ELF文件由4部分组成,分别是ELF头(ELF header)、程序头表(Program header table)、节(Section)和节头表(Section header table)。 +由于ELF 文件内部包含了足够的信息,操作系统可以根据ELF 可执行文件创建出进程映像,进程映像以及各种管理数据结构构成了进程实体,另外进程还可能向系统申请各种资源——共同组成了进程实体的全部内涵。进程实体被调度运行就构成了进程的活动,如果系统中有多个活动的进程,那么它们各自有独立的进程空间(各自独立地使用自己的0~0xFFFFFFFF 虚存空间)。
+在Linux 中进程PCB 是task_struct 结构体,
+ +### 进程间组织关系
+Linux 系统中所有进程通过进程控制块PCB(struct task_struct)形成多种组织关系。根据 +进程创建过程可以有亲缘关系,通过进程间的父子关系组织成一个进程树
+一个进程通过创建一个子进程则形成父子关系,如果创建多个子进程,那么这些新创建的 +进程间属于兄弟关系
+### 2-3 pstree 输出 +![image](./record/pic/2-3.png) +### 2-4 查看会话、进程组和控制终端的例子 +![image](./record/pic/2-4.png) +### PPID +PPID(PPID,Parent PID) PID(进程ID) PGID(Process Group ID 进程组 ID号) SID(Session ID 会话ID) TTY TPGID(tty process group ID for the process group leader) STAT() UID TIME COMMAND
+STAT:D 无法中断的休眠状态(通常 IO 的进程);R 正在运行可中在队列中可过行的;S 处于休眠状态;T 停止或被追踪;W 进入内存交换(从内核2.6开始无效);X 死掉的进程(从来没见过);Z 僵尸进程;+ 位于后台的进程组
+“会话/进程组/线程组”几个概念呈现层级关系,Linux 系统中可以有多个会话(session), +每个会话可以包含多个进程组(process group),每个进程组可以包含多个进程,每个进程构 +成一个线程组——一个线程组由一个进程内的一个或多个线程组成,这些对象都有各自的ID。会话是从用户登录系统到退出前的全部活动,不同帐户的登录属于不同会话,而同一帐户的多次登录也构成不同的会话。而进程组主要出于作业控制的目的,有些shell 没有作用控制能力,就将整个会话的所有进程构成一个进程组。 +### 2-5 创建进程的命令 +```bash +chmod a+x shell-script +shell-script +``` +![image](./record/pic/2-5.png) +第一行用于指出该脚本需要用/usr/bin/bash 来解 +释执行,第二行shell 内部命令echo 用来显示,第三行HelloWorld 是外部命令(磁盘上的可执 +行文件)。 +### 2-6 通过ps 查找进程的PID +1.查找进程的PID
+2.kill PID
+```bash +ps -ef | grep HelloWorld-getchar +``` +![image](./record/pic/2-6.png) +### 2-7 fork-demo 的输出 +![image](./record/pic/2-7.png) +fork 函数被成功调用后将按照父进程的样子复制出一个完全相同的子进程。父进程fork() +函数结束时的返回值是子进程的PID 编号。新创建的子进程则也是从fork()返回处开始执行, +但不同的是它获得的返回值是0。也就是说父子进程执行上几乎相同,
+* 唯一区别是子进程中返回0 值而父进程中返回子进程PID。
+* 如果fork()出错则只有父进程获得返回值-1 而子进程未能创建。
+### 2-8 fork-demo 的输出 +![image](./record/pic/2-8.png) +### 2-9 fork-twice-demo 执行后的 输出 +![image](./record/pic/2-9.png) +### 孤儿进程和僵尸进程 +(1) 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init 进程(进程号为1)所收养,并由init 进程对它们完成状态收集工作。 +(2) 僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。 + 子进程结束后大部分资源都将直接回收,但是还将在PCB(struct task_struct 和内核堆栈)中记录一些退出时的状态等信息,这些信息供父进程检查后才能销毁回收。因此,僵尸进程因相应的数据没有父进程处理并回收,将会导致资源浪费,而孤儿则不会有这样的问题。 +* 孤儿进程 +![image](./record/pic/孤儿进程.png) +* 僵尸进程 +![image](./record/pic/僵尸进程.png) +### 2-10 fork-exec-demo 的执行结果 +![image](./record/pic/2-10.png) +* 这里可以看到子进程通过execve()将自己变身为“/usr/bin/ls”,因此不再执行与父进程里的代——即后面的“printf("this printf()will not be executed, because …”是没有机会得到执行的。 +* fork()和exec 函数族构成了创建新进程的完整操作,如果父子进程功能相同则只用fork(),如果父子进程不同则利用exec 函数族的来实现。 +### 2-11 用ps –ajx 查看daemon-demo 守护进程 +![image](./record/pic/2-11.png) +关闭daemon-demo运行终端后仍能找到daemon-demo进程,且PID为1 +### 2-12 /etc/rsyslog.conf 中的内容 +![image](./record/pic/2-12.png) +日志信息写入了/var/log/messages 文件中。 +### 2-13 查看/var/log/messages +![image](./record/pic/2-13.png) +由于前后运行了多次,所以出现了3个。 +### 2-14&2-15 pthread-demo 的输出及ps –aLf 的输出 +![image](./record/pic/2-14&2-15.png) +两个线程公用一个PID号19392,但是LWP却不一样。 + +### 2-16&2-17 PCB 开销 +```bash +cat /proc/slabinfo | grep task_struct +``` +比较两者在进程控制块上的开销(包括 struct task_struct 和内核栈) +2-16 fork-100-demo 运行前后的/proc/slabinfo 中关于 task_struct 数量 +![image](./record/pic/2-16.png) +2-17 pthread-100-demo 运行前后的/proc/slabinfo 中关于 task_struct 数量 +![image](./record/pic/2-17.png) +两者在运行后的task_struct数量均增加100,说明线程作为调度执行单位,进程控制块PCB(task_struct)还是需要的,这是最小资源的一部分。因此这方面资源开销对进程和线程都是一样的。 +### 2-18&2-19&2-20&2-21内存描述符开销 +* 查看mm_struct数量 +```bash +cat /proc/slabinfo | grep mm_struct +``` +2-18 fork-100-demo 运行前后的/proc/slabinfo 中关于 mm_struct 数量 +![image](./record/pic/2-18.png) +2-19 pthread-100-demo 运行前后的/proc/slabinfo 中关于 mm_struct 数量 +![image](./record/pic/2-19.png) +前者运行时mm_struct数量增加了100,而后者没有变化,说明,pthread-100-demo 虽然创建了 100 个线程,但是用于共享进程空间,并没有增加一个 mm_struct +* 查看vm_area_struct数量 +```bash +cat /proc/slabinfo | grep vm_area_struct +``` +2-20 fork-100-demo 运行前后的/proc/slabinfo 中关于 vm_area_struct 数量 +![image](./record/pic/2-20.png) +2-21 pthread-100-demo 运行前后的/proc/slabinfo 中关于 vm_area_struct 数量 +![image](./record/pic/2-21.png) +可以发现pthread-100-demo需要新增大约 150 左右的使用量,而fork-100-demo需要约 1300 左右的使用量,故线程的开销确实比进程要小。 + +## 课后作业 +### 1.编写 C 语言程序,利用 fork()创建子进程,形成以下父子关系:并通过 ps 命令检查进程的进程号 PID 和父进程号 PPID 证明你成功创建相应的父子关系,同时也用 pstree 输出进程树结构来验证其关系。 +![image](./homework/pic/problem_1.png) +* 解答: +* (1).[code](./homework/code/1_topology_1.c) + ![image](./homework/pic/1_topology_1.png) +可以看到父进程12232拥有10个子进程且满足题目的要求 +* (2).[code](./homework/code/1_topology_2.c) + ![image](./homework/pic/1_topology_2.png) +可以看到父进程13738拥有10个子进程且满足题目的要求 +* (3).[code](./homework/code/1_topology_3.c) + ![image](./homework/pic/1_topology_3.png) +可以看子进程结构满足题目要求。 +### 3.创建多个线程,在各个线程中打印出堆栈变量的地址,大致标记出其位置,注意区分主线程的堆栈和其他线程堆栈位置的差异。 +* 解答:[code](./homework/code/3_pthread.c) +注意:编译时需要链接文件-lpthread -rdynamic +```bash +gcc ./3_pthread.c -lpthread -rdynamic -o 3_pthread +``` + ![image](./homework/pic/3_pthread.png) + 程序中有一个父线程以及3个子线程,可以发现子线程的偏移地址以及返回地址都是一样的,且斗与父线程不一样。 + +### 4.尝试自行设计一个 C 语言小程序,完成最基本的 shell 角色:给出命令行提示符、能够接受命令;对于命令分成三种,内部命令(例如 help 命令、exit 命令等)、外部命令(常见的 ls、cp 等,以及其他磁盘上的可执行程序 HelloWrold 等)以及无效命令(不是上述两种命令)。 + * 解答:[code](./homework/code/shell.c) +![image](./homework/pic/4_shell.png) + +捕获键盘输入->判断是那种命令-> +* 1.内部命令:打印help文件或exit(0);退出
+* 2.外部命令,fork出新的进程并使用execvp函数执行 +* 3.可执行程序,与外部命令方法相同 +* 4.无效命令:打印无效警告 diff --git "a/3.\350\277\233\347\250\213\350\260\203\345\272\246/record/code/RR-FIFO-sched" "b/3.\350\277\233\347\250\213\350\260\203\345\272\246/record/code/RR-FIFO-sched" old mode 100755 new mode 100644 diff --git "a/3.\350\277\233\347\250\213\350\260\203\345\272\246/record/code/RR-FIFO.sh" "b/3.\350\277\233\347\250\213\350\260\203\345\272\246/record/code/RR-FIFO.sh" old mode 100755 new mode 100644 diff --git "a/3.\350\277\233\347\250\213\350\260\203\345\272\246/note.md" "b/3.\350\277\233\347\250\213\350\260\203\345\272\246/report.md" similarity index 86% rename from "3.\350\277\233\347\250\213\350\260\203\345\272\246/note.md" rename to "3.\350\277\233\347\250\213\350\260\203\345\272\246/report.md" index 3a7b66e8cb1d3de42c79948083cfbd99eae22a47..5630153a3af1aca0fd629626b98d1d90273b3639 100644 --- "a/3.\350\277\233\347\250\213\350\260\203\345\272\246/note.md" +++ "b/3.\350\277\233\347\250\213\350\260\203\345\272\246/report.md" @@ -1,225 +1,236 @@ -# 实验记录 -#### 3-1 /proc/cpuinfo 信息 -```bash -cat /proc/cpuinfo -``` -![image](./record/pic/3-1.png) -CPU型号为Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz,拥有四核心八线程 -#### 3-2 top 命令的输出 -```bash -top -``` -![image](./record/pic/3-2.png) -其中 7.7 us 表示 7.7%的时间用于运行用户空间的代码,相应地有 sy 对应运行内核代码占用 CPU 时间的百分比、ni 表示低优先级用户态代码占用 CPU时间的百分比、id 表示空闲(运行 idle 任务进程)CPU 时间的百分比、wa 表示 IO 等待占用CPU 时间的百分比、hi 表示硬件中断(Hardware IRQ)占用 CPU 时间的百分比、si 表示软中断(Software Interrupts)占用 CPU 时间的百分比以及和虚拟化有关的 st(steal time)占用 CPU时间的百分比。 -#### 3-3 top 命令的输出(展开 CPU 利用率) -![image](./record/pic/3-3.png) -#### 3-4&3-5 全系统的调度统计 -```bash -cat /proc/sched_debug -cat /proc/schedstat -``` -![image](./record/pic/3-4.png) -![image](./record/pic/3-5.png) -#### 3-6 ps –aux 查看进程状态 -```bash -ps -aux -``` -![image](./record/pic/3-6.png) -* R:TASK_RUNNING 可执行状态,包括就绪和正在 CPU 上执行 -* S:TASK_INTERRUPTIBLE 可中断的睡眠状态,也是操作系统课程中所谓的阻塞状态 -* D:TASK_UNINTERRUPTIBLE 不可中断的睡眠状态 -* T:TASK_STOPPED 或 TASK_TRACED 暂停状态或跟踪状态 -* Z:TASK_DEAD(-EXIT_ZOMBIE) 退出状态,且成为僵尸进程 -* X:TASK_DEAD(-EXIT_DEAD) 退出状态,且进程即将被销毁 -#### 3-7&3-8 就绪与阻塞 -3-7 HelloWorld-loop-getchar 的运行输出 -![image](./record/pic/3-7.png)
-3-8 用 ps 观察 HelloWorld-loop-getchar 进程调度状态变化 -```bash -ps aux|grep HelloWorld-loop-getchar -``` -![image](./record/pic/3-8.png) - -#### 3-9&3-10 进程的调度统计 -```bash -cat /proc/15366/status -``` -![image](./record/pic/3-9.png) -进程主动切换的次数8,进程主动切换的次数213
- -```bash -cat /proc/15363/stat -``` -![image](./record/pic/3-10.png) - -#### 3-11&3-12&3-13&3-14普通进程的 CFS 调度 -* nice 命令可以用-xx 给出调整的数值(降低优先级 xx),也可以用“-n xx”方式直接设定 NICE 值(- -20~19) -* taskset -c 0 在命令前加上这条语句可以绑定进程运行在制定CPU
- -3-11 执行 Run-NICE.sh 脚本并用 ps –a 查看 -![image](./record/pic/3-11.png)
- -3-12 用 top 观察优先权不同的两个进程 -![image](./record/pic/3-12.png) -16460 号进程占用了 CPU 的 90.4%的时间,16461 号进程仅占用了 CPU 的 9.6%的时间。
- -3-13 /proc/PID/sched -![image](./record/pic/3-13_1.png) -![image](./record/pic/3-13_2.png)
-3-14 /proc/PID/schedstat -![image](./record/pic/3-14.png) - -#### 3-15&3-16创建实时进程 -* 以 root 身份运行 RT-process-demo 进程,如果以普通用户运行 RT-process-demo 则会报告不允许创建实时进程。
-* 实时任务的均衡原则很简单,对于 N 个处理器的系统,保证优先级最高的 N 个实时任务各自在一个处理器上运行。如果实时任务少于 N 个,则多出来的处理器可以运行普通 CFS 任务。 - -3-15 用 ps –al 观察 RT-process-demo 的四个观测点 -![image](./record/pic/3-15a.png) -![image](./record/pic/3-15b.png) -![image](./record/pic/3-15c.png) -![image](./record/pic/3-15d.png)
-3-16 用/proc/PID/sched 观察 RT-process-demo 的四个观测点 -![image](./record/pic/3-16a.png)
- -![image](./record/pic/3-16b.png)
- -![image](./record/pic/3-16c.png)
- -![image](./record/pic/3-16d.png)
- -#### 3-17 创建实时进程 -```bash -sudo taskset -c 0 ./RR-FIFO.sh -``` -经过多次测试发现实验结果无法在ubuntu18.04 多核处理(非虚拟机)器下复现,故改用centOS7进行实验
-top 命令查看高优先级实时进程10047 抢占 CPU -![image](./record/pic/3-17a.png) -![image](./record/pic/3-17b.png) -![image](./record/pic/3-17c.png) - -3-17 运行脚本并查看三个实时进程的调度信息 -```bash -# cat ./sched-10044; cat ./sched-10045; cat ./sched-10047 -RR-FIFO-sched (10044, #threads: 1) -------------------------------------------------------------------- -nr_involuntary_switches : 198 -se.load.weight : 1024 -policy : 2实时任务的均衡原则很简单,对于 N 个处理器的系统,保证优先级最高的 N 个实时任务 -各自在一个处理器上运行。如果实时任务少于 N 个,则多出来的处理器可以运行普通 CFS 任 -务。 -prio : 9 -------------------------------------------------------------------- -nr_involuntary_switches : 199 -se.load.weight : 1024 -policy : 2 -prio : 9 -------------------------------------------------------------------- -nr_involuntary_switches : 25 -se.load.weight : 1024 -policy : 1 -prio : 4 -``` -#### 3-20 ~ 3-26 CFS 进程的负载均衡 -执行 HelloWorld-loop-nice+5/+15 并查看它们的负载权重. -![image](./record/pic/3-18.png) -可以发现负载权重相差了3*3=9倍 - -3-20 显示进程所在处理器编号的 top 输出 -top命令后按 f 进入管理界面根据提示操作打开Last Used Cpu -![image](./record/pic/3-20.png) - -3-21 空闲系统上的即时负载情况 -![image](./record/pic/3-21.png) - -3-22 用 top 查看四个 NICE=-5 的进程所在 CPU -![image](./record/pic/3-22.png) -可以发现4个进程被分配在4个不同的CPU核心上运行 - -FIFO 任务执 -行时不被打断一直到运行结束(除非更高优先级的实时任务来抢占),而后者的 RR 任务在执 -行一个时间片之后将让出 CPU 给其他相同优先级的 RR 任务实现轮转执行。3-23 察看运行-5/0/+5/+10 四个进程后各处理器负载 -![image](./record/pic/3-23.png) - -3-24 从/proc/PID/sched 中查看进程的迁移次数 -处理的进程数小于等于处理器核心数,基本不会进行调度 -![image](./record/pic/3-24.png) - -3-25 用 top 查看五个进程的处理器编号 -在这个情况下处理的进程数大于处理器核心数,故会不断进行调度 -![image](./record/pic/3-25a.png) -![image](./record/pic/3-25b.png) -![image](./record/pic/3-25c.png) - -3-26 用/proc/PID/sched 查看进程迁移次数 -![image](./record/pic/3-26.png) - -#### 3-27&3-28实时进程负载均衡 -进程在八个处理器上运行 -![image](./record/pic/3-27.png) - -高优先级实时进程抢占低优先级实时进程的示例,开启一个优先级更高的进程 -![image](./record/pic/3-28.png) - -# 课后作业 -#### 1.在一个空闲的单核 Linux 系统上用 nice 命令调整两个进程的优先级,使得它们各自使用 1/5 和 4/5 的 CPU 资源。 -```bash -cat Run-NICE.sh -taskset -c 0 ./HelloWorld-loop & -taskset -c 0 nice -6 ./HelloWorld-loop & -``` -运行结果如下: -![image](./homework/1/1.png) - -#### 2.P1/P3 在第一个处理器上运行各占 50%的 CPU 资源,P2/P4 在另一个处理器上运行,各自 30%和 70%的 CPU 资源。 -```bash -cat Run-NICE.sh -taskset -c 0 ./HelloWorld-loop & -taskset -c 0 nice -4 ./HelloWorld-loop & -taskset -c 1 ./HelloWorld-loop & -taskset -c 1 ./HelloWorld-loop & -``` -运行结果如下: -![image](./homework/2/2.png) - -#### 3.请预测 Linux 对于相同优先级的 FIFO 实时进程的调度情况,并通过实验给出实测数据以证明。 -教材中提到: -* FIFO 任务执行时不被打断一直到运行结束(除非更高优先级的实时任务来抢占),而后者的 RR 任务在执行一个时间片之后将让出 CPU 给其他相同优先级的 RR 任务实现轮转执行。 -* FIFO 由于避免了调度切换的时间开销,因此更有利于本任务的快速完成。但是同时由于FIFO 也会造成同级 FIFO 任务的明显延迟. - -故可以猜测 Linux 对于相同优先级的 FIFO 实时进程会安装先进先出的原则执行完一个进程后再执行另外一个。 -实验结果如下: -1.启动两个相同优先级的FIFO 实时进程 -![image](./homework/3/3_homework_3_1.png) -2.观察top结合1的打印结果,发现只有一个成功执行 -![image](./homework/3/3_homework_3_2.png) -3.一段时间后第一个进程执行完毕,第二进程PID号才打印了出来,说明两者运行互斥 -![image](./homework/3/3_homework_3_3.png) -![image](./homework/3/3_homework_3_4.png) - -#### 4.在一个空载的系统上,如果将代码 3-8 的最后一行替换成两个“RR-FIFO-sched 2 80”,请预测其负载均衡后进程的运行情况,并说明是否只有一种处理器分配方案? - -```bash -cat RT-Balance.sh -./RR-FIFO-sched 1 5& -./RR-FIFO-sched 1 10& -./RR-FIFO-sched 1 15& -./RR-FIFO-sched 1 20& -./RR-FIFO-sched 1 25& -./RR-FIFO-sched 1 30& -./RR-FIFO-sched 1 35& -./RR-FIFO-sched 2 80& -./RR-FIFO-sched 2 80 -``` -知识点: -* 以 O(1)调度器方式调度——本处理器上的实时进程按照优先级不同挂入不同的子队列中,高优先级的队列先执行完再执行低优先级的队列上的进程。 -* 实时进程可以进一步分为两种调度模式:SCHED_FIFO 和 SCHED_RR。前者的 FIFO 任务执行时不被打断一直到运行结束(除非更高优先级的实时任务来抢占),而后者的 RR 任务在执行一个时间片之后将让出 CPU 给其他相同优先级的 RR 任务实现轮转执行。 - -预测:后面运行的RR-FIFO-sched 2 80拥有高的优先级故会挂载进队列并开始运行,最低优先级的./RR-FIFO-sched 1 5 被挤出队列,待其他进程完成后再运行 - -实际结果(一开始运行就卡炸了): -首先,8个优先级较高的开始运行,最高占用不超过95% -此时可以观察到8个进程所占用的CPU核心会发生跳动 -![image](./homework/4/4-1.png) -待8个优先级较高的进程执行完成后,优先级较低的进程开始执行 +[toc] +## 实验目的 +* 通过编程实践、观察,学习内存管理的方式。 +## 实验环境 +* 硬件 +1.Intel(R) Xeon(R) Bronze 3104 CPU @ 1.70GHz +2.DDR4 16G +* 软件 +1.CentOS 7 +2.ubuntu 18.04 +3.VMware Workstation Pro 15 +## 实验记录 +### 3-1 /proc/cpuinfo 信息 +```bash +cat /proc/cpuinfo +``` +![image](./record/pic/3-1.png) +CPU型号为Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz,拥有四核心八线程 +### 3-2 top 命令的输出 +```bash +top +``` +![image](./record/pic/3-2.png) +其中 7.7 us 表示 7.7%的时间用于运行用户空间的代码,相应地有 sy 对应运行内核代码占用 CPU 时间的百分比、ni 表示低优先级用户态代码占用 CPU时间的百分比、id 表示空闲(运行 idle 任务进程)CPU 时间的百分比、wa 表示 IO 等待占用CPU 时间的百分比、hi 表示硬件中断(Hardware IRQ)占用 CPU 时间的百分比、si 表示软中断(Software Interrupts)占用 CPU 时间的百分比以及和虚拟化有关的 st(steal time)占用 CPU时间的百分比。 +### 3-3 top 命令的输出(展开 CPU 利用率) +![image](./record/pic/3-3.png) +### 3-4&3-5 全系统的调度统计 +```bash +cat /proc/sched_debug +cat /proc/schedstat +``` +![image](./record/pic/3-4.png) +![image](./record/pic/3-5.png) +### 3-6 ps –aux 查看进程状态 +```bash +ps -aux +``` +![image](./record/pic/3-6.png) +* R:TASK_RUNNING 可执行状态,包括就绪和正在 CPU 上执行 +* S:TASK_INTERRUPTIBLE 可中断的睡眠状态,也是操作系统课程中所谓的阻塞状态 +* D:TASK_UNINTERRUPTIBLE 不可中断的睡眠状态 +* T:TASK_STOPPED 或 TASK_TRACED 暂停状态或跟踪状态 +* Z:TASK_DEAD(-EXIT_ZOMBIE) 退出状态,且成为僵尸进程 +* X:TASK_DEAD(-EXIT_DEAD) 退出状态,且进程即将被销毁 +### 3-7&3-8 就绪与阻塞 +3-7 HelloWorld-loop-getchar 的运行输出 +![image](./record/pic/3-7.png)
+3-8 用 ps 观察 HelloWorld-loop-getchar 进程调度状态变化 +```bash +ps aux|grep HelloWorld-loop-getchar +``` +![image](./record/pic/3-8.png) + +### 3-9&3-10 进程的调度统计 +```bash +cat /proc/15366/status +``` +![image](./record/pic/3-9.png) +进程主动切换的次数8,进程主动切换的次数213
+ +```bash +cat /proc/15363/stat +``` +![image](./record/pic/3-10.png) + +### 3-11&3-12&3-13&3-14普通进程的 CFS 调度 +* nice 命令可以用-xx 给出调整的数值(降低优先级 xx),也可以用“-n xx”方式直接设定 NICE 值(- +20~19) +* taskset -c 0 在命令前加上这条语句可以绑定进程运行在制定CPU
+ +3-11 执行 Run-NICE.sh 脚本并用 ps –a 查看 +![image](./record/pic/3-11.png)
+ +3-12 用 top 观察优先权不同的两个进程 +![image](./record/pic/3-12.png) +16460 号进程占用了 CPU 的 90.4%的时间,16461 号进程仅占用了 CPU 的 9.6%的时间。
+ +3-13 /proc/PID/sched +![image](./record/pic/3-13_1.png) +![image](./record/pic/3-13_2.png)
+3-14 /proc/PID/schedstat +![image](./record/pic/3-14.png) + +### 3-15&3-16创建实时进程 +* 以 root 身份运行 RT-process-demo 进程,如果以普通用户运行 RT-process-demo 则会报告不允许创建实时进程。
+* 实时任务的均衡原则很简单,对于 N 个处理器的系统,保证优先级最高的 N 个实时任务各自在一个处理器上运行。如果实时任务少于 N 个,则多出来的处理器可以运行普通 CFS 任务。 + +3-15 用 ps –al 观察 RT-process-demo 的四个观测点 +![image](./record/pic/3-15a.png) +![image](./record/pic/3-15b.png) +![image](./record/pic/3-15c.png) +![image](./record/pic/3-15d.png)
+3-16 用/proc/PID/sched 观察 RT-process-demo 的四个观测点 +![image](./record/pic/3-16a.png)
+ +![image](./record/pic/3-16b.png)
+ +![image](./record/pic/3-16c.png)
+ +![image](./record/pic/3-16d.png)
+ +### 3-17 创建实时进程 +```bash +sudo taskset -c 0 ./RR-FIFO.sh +``` +经过多次测试发现实验结果无法在ubuntu18.04 多核处理(非虚拟机)器下复现,故改用centOS7进行实验
+top 命令查看高优先级实时进程10047 抢占 CPU +![image](./record/pic/3-17a.png) +![image](./record/pic/3-17b.png) +![image](./record/pic/3-17c.png) + +3-17 运行脚本并查看三个实时进程的调度信息 +```bash +# cat ./sched-10044; cat ./sched-10045; cat ./sched-10047 +RR-FIFO-sched (10044, #threads: 1) +------------------------------------------------------------------- +nr_involuntary_switches : 198 +se.load.weight : 1024 +policy : 2实时任务的均衡原则很简单,对于 N 个处理器的系统,保证优先级最高的 N 个实时任务 +各自在一个处理器上运行。如果实时任务少于 N 个,则多出来的处理器可以运行普通 CFS 任 +务。 +prio : 9 +------------------------------------------------------------------- +nr_involuntary_switches : 199 +se.load.weight : 1024 +policy : 2 +prio : 9 +------------------------------------------------------------------- +nr_involuntary_switches : 25 +se.load.weight : 1024 +policy : 1 +prio : 4 +``` +### 3-20 ~ 3-26 CFS 进程的负载均衡 +执行 HelloWorld-loop-nice+5/+15 并查看它们的负载权重. +![image](./record/pic/3-18.png) +可以发现负载权重相差了3*3=9倍 + +3-20 显示进程所在处理器编号的 top 输出 +top命令后按 f 进入管理界面根据提示操作打开Last Used Cpu +![image](./record/pic/3-20.png) + +3-21 空闲系统上的即时负载情况 +![image](./record/pic/3-21.png) + +3-22 用 top 查看四个 NICE=-5 的进程所在 CPU +![image](./record/pic/3-22.png) +可以发现4个进程被分配在4个不同的CPU核心上运行 + +FIFO 任务执 +行时不被打断一直到运行结束(除非更高优先级的实时任务来抢占),而后者的 RR 任务在执 +行一个时间片之后将让出 CPU 给其他相同优先级的 RR 任务实现轮转执行。3-23 察看运行-5/0/+5/+10 四个进程后各处理器负载 +![image](./record/pic/3-23.png) + +3-24 从/proc/PID/sched 中查看进程的迁移次数 +处理的进程数小于等于处理器核心数,基本不会进行调度 +![image](./record/pic/3-24.png) + +3-25 用 top 查看五个进程的处理器编号 +在这个情况下处理的进程数大于处理器核心数,故会不断进行调度 +![image](./record/pic/3-25a.png) +![image](./record/pic/3-25b.png) +![image](./record/pic/3-25c.png) + +3-26 用/proc/PID/sched 查看进程迁移次数 +![image](./record/pic/3-26.png) + +### 3-27&3-28实时进程负载均衡 +进程在八个处理器上运行 +![image](./record/pic/3-27.png) + +高优先级实时进程抢占低优先级实时进程的示例,开启一个优先级更高的进程 +![image](./record/pic/3-28.png) + +## 课后作业 +### 1.在一个空闲的单核 Linux 系统上用 nice 命令调整两个进程的优先级,使得它们各自使用 1/5 和 4/5 的 CPU 资源。 +```bash +cat Run-NICE.sh +taskset -c 0 ./HelloWorld-loop & +taskset -c 0 nice -6 ./HelloWorld-loop & +``` +运行结果如下: +![image](./homework/1/1.png) + +### 2.P1/P3 在第一个处理器上运行各占 50%的 CPU 资源,P2/P4 在另一个处理器上运行,各自 30%和 70%的 CPU 资源。 +```bash +cat Run-NICE.sh +taskset -c 0 ./HelloWorld-loop & +taskset -c 0 nice -4 ./HelloWorld-loop & +taskset -c 1 ./HelloWorld-loop & +taskset -c 1 ./HelloWorld-loop & +``` +运行结果如下: +![image](./homework/2/2.png) + +### 3.请预测 Linux 对于相同优先级的 FIFO 实时进程的调度情况,并通过实验给出实测数据以证明。 +教材中提到: +* FIFO 任务执行时不被打断一直到运行结束(除非更高优先级的实时任务来抢占),而后者的 RR 任务在执行一个时间片之后将让出 CPU 给其他相同优先级的 RR 任务实现轮转执行。 +* FIFO 由于避免了调度切换的时间开销,因此更有利于本任务的快速完成。但是同时由于FIFO 也会造成同级 FIFO 任务的明显延迟. + +故可以猜测 Linux 对于相同优先级的 FIFO 实时进程会安装先进先出的原则执行完一个进程后再执行另外一个。 +实验结果如下: +1.启动两个相同优先级的FIFO 实时进程 +![image](./homework/3/3_homework_3_1.png) +2.观察top结合1的打印结果,发现只有一个成功执行 +![image](./homework/3/3_homework_3_2.png) +3.一段时间后第一个进程执行完毕,第二进程PID号才打印了出来,说明两者运行互斥 +![image](./homework/3/3_homework_3_3.png) +![image](./homework/3/3_homework_3_4.png) + +### 4.在一个空载的系统上,如果将代码 3-8 的最后一行替换成两个“RR-FIFO-sched 2 80”,请预测其负载均衡后进程的运行情况,并说明是否只有一种处理器分配方案? + +```bash +cat RT-Balance.sh +./RR-FIFO-sched 1 5& +./RR-FIFO-sched 1 10& +./RR-FIFO-sched 1 15& +./RR-FIFO-sched 1 20& +./RR-FIFO-sched 1 25& +./RR-FIFO-sched 1 30& +./RR-FIFO-sched 1 35& +./RR-FIFO-sched 2 80& +./RR-FIFO-sched 2 80 +``` +知识点: +* 以 O(1)调度器方式调度——本处理器上的实时进程按照优先级不同挂入不同的子队列中,高优先级的队列先执行完再执行低优先级的队列上的进程。 +* 实时进程可以进一步分为两种调度模式:SCHED_FIFO 和 SCHED_RR。前者的 FIFO 任务执行时不被打断一直到运行结束(除非更高优先级的实时任务来抢占),而后者的 RR 任务在执行一个时间片之后将让出 CPU 给其他相同优先级的 RR 任务实现轮转执行。 + +预测:后面运行的RR-FIFO-sched 2 80拥有高的优先级故会挂载进队列并开始运行,最低优先级的./RR-FIFO-sched 1 5 被挤出队列,待其他进程完成后再运行 + +实际结果(一开始运行就卡炸了): +首先,8个优先级较高的开始运行,最高占用不超过95% +此时可以观察到8个进程所占用的CPU核心会发生跳动 +![image](./homework/4/4-1.png) +待8个优先级较高的进程执行完成后,优先级较低的进程开始执行 ![image](./homework/4/4-2.png) \ No newline at end of file diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/msgtool" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/msgtool" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/mutex-demo" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/mutex-demo" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/no-mutex-demo" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/no-mutex-demo" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/pipe-demo" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/pipe-demo" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/psem-named-open" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/psem-named-open" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/psem-named-post-demo" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/psem-named-post-demo" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/psem-named-wait-demo" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/psem-named-wait-demo" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/shmatt-read-demo" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/shmatt-read-demo" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/shmatt-write-demo" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/shmatt-write-demo" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/shmget-demo" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/record/code/shmget-demo" old mode 100755 new mode 100644 diff --git "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/note.md" "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/report.md" similarity index 94% rename from "4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/note.md" rename to "4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/report.md" index a0f06f0f1ee86a66442415b15cacc0c85301c8ee..da956ce7814617110a6e1fce0088d2fffe420c8e 100644 --- "a/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/note.md" +++ "b/4.\350\277\233\347\250\213\351\227\264\351\200\232\344\277\241\344\270\216\345\220\214\346\255\245/report.md" @@ -1,253 +1,264 @@ -# 实验记录 -### 4-1 无名管道 -* 管道(pipe),或称无名管道,是所有 Unix 都提供的一种进程间通信机制。 -* Unix 命令中使用“|”来连接两个命令时使用的就是管道,例如“ls | more” -* 无名管道有一个主要缺点,只能通过父子进程之间(及其后代)使用文件描述符的继承来访问,无法在任意的进程之间使用。 - -屏显 4-1 pipe-demo 的输出 -![image](./record/pic/4-1.png) - -### 4-2&4-3&4-4 命名管道(FIFO) -* FIFO 就是无名管道的升级版——有可访问的磁盘索引节点,即 FIFO 文件将出现在目录树中(不像无名管道那样只存在于 pipefs 特殊文件系统中) - -4-2 mkfifo 创建命名管道 -4-3 用 cat 尝试读取空的管道文件(阻塞) -![image](./record/pic/4-2.png) - -4-4 用 echo 向管道写入数据(cat 被唤醒并显示管道文件的内容) -![image](./record/pic/4-4.png) - -### System V IPC -System V IPC 指的是 AT&T 在 System V.2 发行版中引入的三种进程间通信工具: -* (1)信号量,用来管理对共享资源的访问 -* (2)共享内存,用来高效地实现进程间的数据共享 -* (3)消息队列,用来实现进程间数据的传递。 -### ipcs -* 在 Linux 中执行 ipcs 命令可以查看到当前系统中所有的 System V IPC 对象 -* ipcs -a 是默认的输出全部信息、ipcs -m 显示共享内存的信息、ipcs -q 显示消息队列的信息、ipcs -s 显示信号量集的信息。另外用还有一些格式控制的参数,–t 将会输出带时间信息、-p 将输出进程 PID 信息、-c 将输出创建者/拥有者的 PID、-l 输出相关的限制条件。例如用 ipcs -ql 将显示消息队列的限制条件 -```bash -ipcs ---------- 消息队列 ----------- -键 msqid 拥有者 权限 已用字节数 消息 - ------------- 共享内存段 -------------- -键 shmid 拥有者 权限 字节 连接数 状态 -0x00000000 65536 hypo 600 524288 2 目标 -0x00000000 229377 hypo 600 134217728 2 目标 -................................. - ---------- 信号量数组 ----------- -键 semid 拥有者 权限 nsems -``` -```bash -ipcs -ql - ----------- 消息限制 ----------- -系统最大队列数量 = 32000 -最大消息尺寸 (字节) = 8192 -默认的队列最大尺寸 (字节) = 16384 -``` -### 4-5 消息队列 -屏显 4-5 msgtool 的执行结果 -```bash -(base) $ ./msgtool s 1 Hello,my_msq_queue! -Sending a message -(base)$ ipcs -q - ---------- 消息队列 ----------- -键 msqid 拥有者 权限 已用字节数 消息 -0x6d060ca4 0 hypo 660 20 1 - -(base) $ ./msgtool r 1 -Reading a message -Type: 1 Text: Hello,my_msq_queue! -(base)$ ipcs -q - ---------- 消息队列 ----------- -键 msqid 拥有者 权限 已用字节数 消息 -0x6d060ca4 0 hypo 660 0 0 - -``` -### 4-6 ~ 4-10共享内存 -屏显 4-6 shmget-demo 的输出 -```bash -$./shmget-demo -Successfully created segment : 7634968 ------------- 共享内存段 -------------- -键 shmid 拥有者 权限 字节 连接数 状态 - -0x00000000 7241751 hypo 600 524288 2 目标 -0x00000000 7634968 hypo 666 4096 0 - -Successfully created segment : 7438361 -``` -屏显 4-7 shmatt-write-demo 运行时的输出(1) -```bash -$./shmatt-write-demo 7634968 - segment attached at 0x7f24a55f6000 - ------------- 共享内存段 -------------- -键 shmid 拥有者 权限 字节shmatt-write-demo 映射共享内存时的进程布局 - -击键回车后 shmat-write-demo 将解除共享内存的映射,此时 ipcs –m 显示对应的共享内存区没有人使用(nattch 列为 0) - -屏显 4-9 shmatt-demo 运行时的输出(2) - - -$. ipcs -m -​ ------------- 共享内存段 -------------- -键       shmid     拥有者 权限     字节     连接数 状态       -​ -0x00000000 7667735   hypo       600        524288     2         目标       -0x00000000 7634968   hypo       666        4096       0                       -​ -屏显 4-10 shmatt-read-demo 的部分输出 - - -$ ./shmatt-read-demo 7634968 - segment attached at 0x7f19a5aee000 -​ ------------- 共享内存段 -------------- -键       shmid     拥有者 权限     字节     连接数 状态       -0x00000000 7634968   hypo       666        4096       1                       - -The string in SHM is :Hello shared memory! -虽然创建该共享内存的进程已经结束了,可是 shmatt-read-demo 映射 ID 为的共享内存后,仍读出了原来写入的字符串,如所示。 连接数 状态 -0x00000000 7634968 hypo 666 4096 1 -0x00000000 6881306 hypo 600 2738960 2 目标 -``` -屏显 4-8 shmatt-write-demo 映射共享内存时的进程布局 -![image](./record/pic/4-8.png) -击键回车后 shmat-write-demo 将解除共享内存的映射,此时 ipcs –m 显示对应的共享内存区没有人使用(nattch 列为 0) - -屏显 4-9 shmatt-demo 运行时的输出(2) - -```bash -$. ipcs -m - ------------- 共享内存段 -------------- -键 shmid 拥有者 权限 字节 连接数 状态 - -0x00000000 7667735 hypo 600 524288 2 目标 -0x00000000 7634968 hypo 666 4096 0 - -``` -屏显 4-10 shmatt-read-demo 的部分输出 -```bash -$ ./shmatt-read-demo 7634968 - segment attached at 0x7f19a5aee000 - ------------- 共享内存段 -------------- -键 shmid 拥有者 权限 字节 连接数 状态 -0x00000000 7634968 hypo 666 4096 1 - -The string in SHM is :Hello shared memory! -``` -虽然创建该共享内存的进程已经结束了,可是 shmatt-read-demo 映射 ID 为的共享内存后,仍读出了原来写入的字符串,如所示。 -### POSIX 有名信号量 -屏显 4-11 psem-named-open-demo 的输出 -```bash -$ gcc psem-named-open.c -lpthread -o psem-named-open -$ ./psem-named-open -please input a file name to act as the ID of the sem! -$ ./psem-named-open HelloWorld.c -``` -屏显 4-12 ps 查看 psem-named-wait-demo 的运行状态 -![image](./record/pic/4-12.png) - -该信量进行 P 操作(增 1 操作),使得前面的 psem-named-wait-demo 进程从原来的阻塞状态唤醒并执行结束。 -图 4-6 psem-named-post-demo 的运行输出(并唤醒阻塞的 psem-named-wait-demo 进程) -![image](./record/pic/pic4-6.png) - -### POSIX 无名信号量 -POSIX 无名信号量适用于线程间通信,如果无名信号量要用于进程间同步,信号量要放在共享内存中(只要该共享内存区存在,该信号灯就可用)。 -### 互斥量 -屏显 4-13 mutex-demo 的输出 -![image](./record/pic/4-13.png) - -屏显 4-14 mutex-demo 的输出 -(在新版本gcc中mutex m;应改为pthread_mutex_t m;) -![image](./record/pic/4-14.png) - -# 课后作业 -#### 1.设计编写以下程序,着重考虑其通信和同步问题: -* a)一个程序(进程)从命令行读入按键信息,一次将“一整行”按键信息保存到一个共享存储的缓冲区内并等待读取进程将数据读走,不断重复上面的操作; -* b)另一个程序(进程)生成两个进程/线程用于显示缓冲区内的信息,这两个线程并发读取缓冲区信息后将缓冲区清空(一个线程的两次“读取+ 显示”操作之间可以加入适当的时延以便于观察)。 -* c)在两个独立的终端窗口上分别运行上述两个程序,展示其同步与通信功能,要求一次 -只有一个任务在操作缓冲区。 -* d) 运行程序,记录操作过程的截屏并给出文字说明。 -* 要求使用 posix 信号量来完成这里的生产者和消费者的同步关系。 - -解答: -对于本题,编写了两个程序,分别是Comsumer.c与Producer.c -Comsumer.c将创建共享内存区与一个信号量并不断的检测键盘输入,当有键盘输入且信号量为0的时候将键入内容复制到共享内存区,并对信号量加1 -Producer.c被fork为两个线程,不断的检测信号量,若为1则读取内存缓存区并显示,然后对信号量减1 -![image](./homework/Producer_Comsumer.png) - -#### 2.将 2.6 的练习 3 进行扩展,使得你编写的 shell 程序具有支持管道的功能,也就是说你的shell 中输入“dir | more”能够执行 dir 命令并通过管道将其输入传送给 more -解答: -1.创建pipe -2.fork两个子进程执行dir和more命令 -3.把dir子进程的标准输出、标准错误重定向到管道数据入口 -4.把more子进程的标准输入重定向到管道数据出口 - -![image](./homework/shell_with_pipe.png) -[参考资料1](https://blog.csdn.net/weixin_34197488/article/details/93652978) -[参考资料2](http://www.it1352.com/485628.html) -[参考资料3](https://blog.csdn.net/tiandc/article/details/81489447) -实现函数: - -```c -int pipe_shell(char **args1, char **args2) -{ - int pfds[2]; - pid_t pid1, pid2, wpid; - pipe(pfds); - char buf[1024]; - int nwr = 0; - int status; - pid1 = fork(); - if (pid1 < 0) - { - printf("fork error!\n"); - } - else if (pid1 == 0) - { - // STDIN_FILENO:接收键盘的输入 - // STDOUT_FILENO:向屏幕输出 - // dup2 把 pfds[1](管道数据入口描述符) 复制到 文件描述符1&2 - // 实现把pid1的标准输出和标准错误 输送到管道 - dup2(pfds[1], STDOUT_FILENO); - dup2(pfds[1], STDERR_FILENO); - close(pfds[0]); - close(pfds[1]); - char *args[]={"ls",NULL}; - execvp(args1[0], args1); - exit(0); - } - pid2 = fork(); - if (pid2< 0) - { - printf("error!\n"); - } - else if (pid2 == 0){ - //dup2 把 pfds[0](管道数据出口描述符) 复制到 文件描述符0 - //实现pid2从管道中读取(pid1的输出)数据 - dup2(pfds[0], STDIN_FILENO); - close(pfds[0]); - close(pfds[1]); - char *args[]={"more",NULL}; - execvp(args2[0], args2); - exit(0); - } - close(pfds[0]); - close(pfds[1]); - do - { - wpid = waitpid(pid2,&status,WUNTRACED); - } - while (!WIFEXITED(status) && !WIFSIGNALED(status)); - return 1; -} +[toc] +## 实验目的 +* 通过编程实践、观察,学习进程间通信与同步的方法。 +## 实验环境 +* 硬件 +1.Intel(R) Xeon(R) Bronze 3104 CPU @ 1.70GHz +2.DDR4 16G +* 软件 +1.CentOS 7 +2.ubuntu 18.04 +3.VMware Workstation Pro 15 +## 实验记录 +### 4-1 无名管道 +* 管道(pipe),或称无名管道,是所有 Unix 都提供的一种进程间通信机制。 +* Unix 命令中使用“|”来连接两个命令时使用的就是管道,例如“ls | more” +* 无名管道有一个主要缺点,只能通过父子进程之间(及其后代)使用文件描述符的继承来访问,无法在任意的进程之间使用。 + +屏显 4-1 pipe-demo 的输出 +![image](./record/pic/4-1.png) + +### 4-2&4-3&4-4 命名管道(FIFO) +* FIFO 就是无名管道的升级版——有可访问的磁盘索引节点,即 FIFO 文件将出现在目录树中(不像无名管道那样只存在于 pipefs 特殊文件系统中) + +4-2 mkfifo 创建命名管道 +4-3 用 cat 尝试读取空的管道文件(阻塞) +![image](./record/pic/4-2.png) + +4-4 用 echo 向管道写入数据(cat 被唤醒并显示管道文件的内容) +![image](./record/pic/4-4.png) + +### System V IPC +System V IPC 指的是 AT&T 在 System V.2 发行版中引入的三种进程间通信工具: +* (1)信号量,用来管理对共享资源的访问 +* (2)共享内存,用来高效地实现进程间的数据共享 +* (3)消息队列,用来实现进程间数据的传递。 +### ipcs +* 在 Linux 中执行 ipcs 命令可以查看到当前系统中所有的 System V IPC 对象 +* ipcs -a 是默认的输出全部信息、ipcs -m 显示共享内存的信息、ipcs -q 显示消息队列的信息、ipcs -s 显示信号量集的信息。另外用还有一些格式控制的参数,–t 将会输出带时间信息、-p 将输出进程 PID 信息、-c 将输出创建者/拥有者的 PID、-l 输出相关的限制条件。例如用 ipcs -ql 将显示消息队列的限制条件 +```bash +ipcs +--------- 消息队列 ----------- +键 msqid 拥有者 权限 已用字节数 消息 + +------------ 共享内存段 -------------- +键 shmid 拥有者 权限 字节 连接数 状态 +0x00000000 65536 hypo 600 524288 2 目标 +0x00000000 229377 hypo 600 134217728 2 目标 +................................. + +--------- 信号量数组 ----------- +键 semid 拥有者 权限 nsems +``` +```bash +ipcs -ql + +---------- 消息限制 ----------- +系统最大队列数量 = 32000 +最大消息尺寸 (字节) = 8192 +默认的队列最大尺寸 (字节) = 16384 +``` +### 4-5 消息队列 +屏显 4-5 msgtool 的执行结果 +```bash +(base) $ ./msgtool s 1 Hello,my_msq_queue! +Sending a message +(base)$ ipcs -q + +--------- 消息队列 ----------- +键 msqid 拥有者 权限 已用字节数 消息 +0x6d060ca4 0 hypo 660 20 1 + +(base) $ ./msgtool r 1 +Reading a message +Type: 1 Text: Hello,my_msq_queue! +(base)$ ipcs -q + +--------- 消息队列 ----------- +键 msqid 拥有者 权限 已用字节数 消息 +0x6d060ca4 0 hypo 660 0 0 + +``` +### 4-6 ~ 4-10共享内存 +屏显 4-6 shmget-demo 的输出 +```bash +$./shmget-demo +Successfully created segment : 7634968 +------------ 共享内存段 -------------- +键 shmid 拥有者 权限 字节 连接数 状态 + +0x00000000 7241751 hypo 600 524288 2 目标 +0x00000000 7634968 hypo 666 4096 0 + +Successfully created segment : 7438361 +``` +屏显 4-7 shmatt-write-demo 运行时的输出(1) +```bash +$./shmatt-write-demo 7634968 + segment attached at 0x7f24a55f6000 + +------------ 共享内存段 -------------- +键 shmid 拥有者 权限 字节shmatt-write-demo 映射共享内存时的进程布局 + +击键回车后 shmat-write-demo 将解除共享内存的映射,此时 ipcs –m 显示对应的共享内存区没有人使用(nattch 列为 0) + +屏显 4-9 shmatt-demo 运行时的输出(2) + + +$. ipcs -m +​ +------------ 共享内存段 -------------- +键       shmid     拥有者 权限     字节     连接数 状态       +​ +0x00000000 7667735   hypo       600        524288     2         目标       +0x00000000 7634968   hypo       666        4096       0                       +​ +屏显 4-10 shmatt-read-demo 的部分输出 + + +$ ./shmatt-read-demo 7634968 + segment attached at 0x7f19a5aee000 +​ +------------ 共享内存段 -------------- +键       shmid     拥有者 权限     字节     连接数 状态       +0x00000000 7634968   hypo       666        4096       1                       + +The string in SHM is :Hello shared memory! +虽然创建该共享内存的进程已经结束了,可是 shmatt-read-demo 映射 ID 为的共享内存后,仍读出了原来写入的字符串,如所示。 连接数 状态 +0x00000000 7634968 hypo 666 4096 1 +0x00000000 6881306 hypo 600 2738960 2 目标 +``` +屏显 4-8 shmatt-write-demo 映射共享内存时的进程布局 +![image](./record/pic/4-8.png) +击键回车后 shmat-write-demo 将解除共享内存的映射,此时 ipcs –m 显示对应的共享内存区没有人使用(nattch 列为 0) + +屏显 4-9 shmatt-demo 运行时的输出(2) + +```bash +$. ipcs -m + +------------ 共享内存段 -------------- +键 shmid 拥有者 权限 字节 连接数 状态 + +0x00000000 7667735 hypo 600 524288 2 目标 +0x00000000 7634968 hypo 666 4096 0 + +``` +屏显 4-10 shmatt-read-demo 的部分输出 +```bash +$ ./shmatt-read-demo 7634968 + segment attached at 0x7f19a5aee000 + +------------ 共享内存段 -------------- +键 shmid 拥有者 权限 字节 连接数 状态 +0x00000000 7634968 hypo 666 4096 1 + +The string in SHM is :Hello shared memory! +``` +虽然创建该共享内存的进程已经结束了,可是 shmatt-read-demo 映射 ID 为的共享内存后,仍读出了原来写入的字符串,如所示。 +### POSIX 有名信号量 +屏显 4-11 psem-named-open-demo 的输出 +```bash +$ gcc psem-named-open.c -lpthread -o psem-named-open +$ ./psem-named-open +please input a file name to act as the ID of the sem! +$ ./psem-named-open HelloWorld.c +``` +屏显 4-12 ps 查看 psem-named-wait-demo 的运行状态 +![image](./record/pic/4-12.png) + +该信量进行 P 操作(增 1 操作),使得前面的 psem-named-wait-demo 进程从原来的阻塞状态唤醒并执行结束。 +图 4-6 psem-named-post-demo 的运行输出(并唤醒阻塞的 psem-named-wait-demo 进程) +![image](./record/pic/pic4-6.png) + +### POSIX 无名信号量 +POSIX 无名信号量适用于线程间通信,如果无名信号量要用于进程间同步,信号量要放在共享内存中(只要该共享内存区存在,该信号灯就可用)。 +### 互斥量 +屏显 4-13 mutex-demo 的输出 +![image](./record/pic/4-13.png) + +屏显 4-14 mutex-demo 的输出 +(在新版本gcc中mutex m;应改为pthread_mutex_t m;) +![image](./record/pic/4-14.png) + +## 课后作业 +### 1.设计编写以下程序,着重考虑其通信和同步问题: +* a)一个程序(进程)从命令行读入按键信息,一次将“一整行”按键信息保存到一个共享存储的缓冲区内并等待读取进程将数据读走,不断重复上面的操作; +* b)另一个程序(进程)生成两个进程/线程用于显示缓冲区内的信息,这两个线程并发读取缓冲区信息后将缓冲区清空(一个线程的两次“读取+ 显示”操作之间可以加入适当的时延以便于观察)。 +* c)在两个独立的终端窗口上分别运行上述两个程序,展示其同步与通信功能,要求一次 +只有一个任务在操作缓冲区。 +* d) 运行程序,记录操作过程的截屏并给出文字说明。 +* 要求使用 posix 信号量来完成这里的生产者和消费者的同步关系。 + +解答: +对于本题,编写了两个程序,分别是Comsumer.c与Producer.c +Comsumer.c将创建共享内存区与一个信号量并不断的检测键盘输入,当有键盘输入且信号量为0的时候将键入内容复制到共享内存区,并对信号量加1 +Producer.c被fork为两个线程,不断的检测信号量,若为1则读取内存缓存区并显示,然后对信号量减1 +![image](./homework/Producer_Comsumer.png) + +### 2.将 2.6 的练习 3 进行扩展,使得你编写的 shell 程序具有支持管道的功能,也就是说你的shell 中输入“dir | more”能够执行 dir 命令并通过管道将其输入传送给 more +解答: +1.创建pipe +2.fork两个子进程执行dir和more命令 +3.把dir子进程的标准输出、标准错误重定向到管道数据入口 +4.把more子进程的标准输入重定向到管道数据出口 + +![image](./homework/shell_with_pipe.png) +[参考资料1](https://blog.csdn.net/weixin_34197488/article/details/93652978) +[参考资料2](http://www.it1352.com/485628.html) +[参考资料3](https://blog.csdn.net/tiandc/article/details/81489447) +实现函数: + +```c +int pipe_shell(char **args1, char **args2) +{ + int pfds[2]; + pid_t pid1, pid2, wpid; + pipe(pfds); + char buf[1024]; + int nwr = 0; + int status; + pid1 = fork(); + if (pid1 < 0) + { + printf("fork error!\n"); + } + else if (pid1 == 0) + { + // STDIN_FILENO:接收键盘的输入 + // STDOUT_FILENO:向屏幕输出 + // dup2 把 pfds[1](管道数据入口描述符) 复制到 文件描述符1&2 + // 实现把pid1的标准输出和标准错误 输送到管道 + dup2(pfds[1], STDOUT_FILENO); + dup2(pfds[1], STDERR_FILENO); + close(pfds[0]); + close(pfds[1]); + char *args[]={"ls",NULL}; + execvp(args1[0], args1); + exit(0); + } + pid2 = fork(); + if (pid2< 0) + { + printf("error!\n"); + } + else if (pid2 == 0){ + //dup2 把 pfds[0](管道数据出口描述符) 复制到 文件描述符0 + //实现pid2从管道中读取(pid1的输出)数据 + dup2(pfds[0], STDIN_FILENO); + close(pfds[0]); + close(pfds[1]); + char *args[]={"more",NULL}; + execvp(args2[0], args2); + exit(0); + } + close(pfds[0]); + close(pfds[1]); + do + { + wpid = waitpid(pid2,&status,WUNTRACED); + } + while (!WIFEXITED(status) && !WIFSIGNALED(status)); + return 1; +} ``` \ No newline at end of file diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1" new file mode 100644 index 0000000000000000000000000000000000000000..5ce560bbeb11379e2ec0db3e4f344221052a965e Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1.c" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1.c" new file mode 100644 index 0000000000000000000000000000000000000000..3efd9810e53cb9dcde14b3d3a6db868d0aa3cc40 --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1.c" @@ -0,0 +1,17 @@ +#include +#include + +#define kB 1024 +void *p; +int main() +{ + int i = 8; + while(1) + { + p = malloc(i*kB); + free(p); + printf("%d,succeed,%s\n",i,p); + i++; + } + return 0; +} diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1.png" new file mode 100644 index 0000000000000000000000000000000000000000..5bbb0dd9d04e2611804e743d4d6eb1545c77c352 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem1.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2" new file mode 100644 index 0000000000000000000000000000000000000000..8303c21ac5f229d9a41bf9c9508173a27fa76fde Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2.c" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2.c" new file mode 100644 index 0000000000000000000000000000000000000000..29422aa4b837e6735c9c523b1ca01a2c44856d97 --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2.c" @@ -0,0 +1,42 @@ +#include +#include +#define kb 1024 + +void *bufs[134]; //1+1+1+2+1+4+1+8+1+16+1+32+1+64 = 134 +// int list[]={0,2,5,10,19,36,69}; + +int main(){ + int i; + for (i = 0; i < 134; ++i){ + bufs[i] = malloc(1*kb); + } + + for (i = 0; i < 134; ++i){ + if (i==0) + printf("<1kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 2) + printf("1~2kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 5) + printf("2~4kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 10) + printf("4-8kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 19) + printf("8-16kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 36) + printf("16-32kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 69) + printf("32-64kb pre-addr:%p\n",bufs[i+1] ); + else + free(bufs[i]); + } + + while(1){ + int size; + printf("input size(<64kb):\n"); + scanf("%d",&size); + void *ptr; + ptr = malloc(size*kb); + printf("true:addr:%p\n",ptr ); + } + return 0; +} \ No newline at end of file diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2.png" new file mode 100644 index 0000000000000000000000000000000000000000..140a94775f154de829d502a8ba013403b32a635c Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem2.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_A.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_A.png" new file mode 100644 index 0000000000000000000000000000000000000000..64417878fadc2d2a8fe34e317e0be132827b4549 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_A.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_a" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_a" new file mode 100644 index 0000000000000000000000000000000000000000..232178db5a43432118c368ab0824d029db0fea17 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_a" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_a.c" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_a.c" new file mode 100644 index 0000000000000000000000000000000000000000..9f5fe4beaa816949868c770fde3b8a9a56dbb7c3 --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_a.c" @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + + +#define MB (1024*1024) + +int main() +{ + int pid,i; + char *buf; + + pid = getpid(); + printf("PID:%d\n",pid ); + + buf=(char*)malloc(1024*MB); + printf("addr_start:%p\n",buf); + + for(i=0;i<1024*MB;i++) + { + buf[i]=0xaa; + } + + printf("addr_end:%p\n",&buf[i]); + + long size = &buf[i]-&buf[0]; + printf("malloc size:%dMB\n", size/MB); + + + printf("please run pages-blackhole-demo\n"); + + getchar(); + + free(buf); + return 0; +} \ No newline at end of file diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_b" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_b" new file mode 100644 index 0000000000000000000000000000000000000000..30e0dafcad821ea70d800f7e8f8c77d873ae6165 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_b" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_b.c" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_b.c" new file mode 100644 index 0000000000000000000000000000000000000000..f2a53c6a63fce7b17588a2af93b4cccc63d421e7 --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_b.c" @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#define MB 1024*1024 +int main() +{ + int i,j; + char temp; + int fd= -1; + char * filemap_buf; + char * anon_buf; + anon_buf=(char *)malloc(1000*MB); + while(1) + { + for(i=0;i<1000*MB;i+=4096) + anon_buf[i]=0xaa; + sleep(1); + } + return 0; +} \ No newline at end of file diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_crash.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_crash.png" new file mode 100644 index 0000000000000000000000000000000000000000..f6307ff664f1963a6e3b5c831bab26fc4a25586b Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_crash.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_free.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_free.png" new file mode 100644 index 0000000000000000000000000000000000000000..daa8cce8dd142a6a30423435b09a9625110780ec Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/homework/problem3_free.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/note.md" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/note.md" deleted file mode 100644 index 9cdb6a6e1434d7e24fce02183846369821b63a10..0000000000000000000000000000000000000000 --- "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/note.md" +++ /dev/null @@ -1,212 +0,0 @@ -# 实验记录 -### 5.1.1 进程映像 -* 屏显 5-1 HelloWorld-getchar 的内存布局 -![image](./record/pic/5-1.png) -每一行是一个具有特定属性的连续的内存区,每行的开头是该区间的地址范围。后面的 rxwp 分别代表:r=可读、w=可写、x=可执行、s=共享以及 p=私有,再后面一列的数字用于表示文件映射内存对应于文件中的起始位置(如果不是文件映射区则为 0)。 -* 屏显 5-2 ELF 可执行文件的节 -```bash -(base) hypo@hypo-CW65S$ readelf -S HelloWorld-getchar -There are 29 section headers, starting at offset 0x1968: -节头: - [号] 名称 类型 地址 偏移量 - 大小 全体大小 旗标 链接 信息 对齐 - [ 0] NULL 0000000000000000 00000000 - 0000000000000000 0000000000000000 0 0 0 -...... - [14] .text PROGBITS 0000000000000580 00000580 - 00000000000001a2 0000000000000000 AX 0 0 16 - [16] .rodata PROGBITS 0000000000000730 00000730 - 0000000000000010 0000000000000000 A 0 0 4 -...... - [23] .data PROGBITS 0000000000201000 00001000 - 0000000000000010 0000000000000000 WA 0 0 8 - [24] .bss NOBITS 0000000000201010 00001010 - 0000000000000008 0000000000000000 WA 0 0 1 -...... -Key to Flags: - W (write), A (alloc), X (execute), M (merge), S (strings), I (info), - L (link order), O (extra OS processing required), G (group), T (TLS), - C (compressed), x (unknown), o (OS specific), E (exclude), - l (large), p (processor specific) -``` -1.其中编号为 13 的.text 节是 Helloworld-getchar.c 编译后的 x86-64 平台上的可执行二进制代码 -2.编号为 23 的.data是用于保存已初始化的全局变量和局部静态变量 -3.编号为 16 的.rodata 是编译器识别出来的只读数据 - -* 屏显 5-3 ELF 段以及段-节映射关系 - ELF 可执行文件的程序头(Program Header)里面描述了与装入过程有关的信息,告知操作系统如何将它们映射到虚拟空间中。我们用 readelf -l 命令查看这些信息 - ![image](./record/pic/5-3.png) - 02 段所对应的节装入到虚存空间VirtAddr=0x0000000000000000 的区域中,而且此虚存空间区域的属性需要设置为“R E”——表示只读和可执行(包括了代码段和只读数据)。 -03 段所对应的节装入到虚存空间VirtAddr=0x0000000000200db0 的区域内,并且其属性 Flags 为“RW”表示可读可写,但不可执行(因为它们都是数据) - -### 5.1.2 堆区 -在堆区分配内存可以用 malloc()等函数来完成,用完后需要用 free()进行释放。malloc()函数的原型如下: -```c -#include -void *malloc(unsigned int num_bytes); -``` -该函数将分配长度为 num_bytes 字节的内存块,如果分配成功则返回指向被分配内存的指针,否则返回空指针 NULL。当内存不再使用时,应使用 free()函数将内存块释放。 -* 屏显 5-4 执行 malloc()之前的内存布局 -![image](./record/pic/5-4.png) -* 屏显 5-5 执行 5 次 malloc()之后的内存布局 -![image](./record/pic/5-5.png) -* 屏显 5-6 执行 2 次 free()之后的内存布局 -![image](./record/pic/5-6.png) -观察[heap]区,由于将 5 次分配的内存释放掉第 2/4 次分配的空间,原来的空间将被分割成多段,但是 Linux 操作系统似乎并没有将这两段区间回收。 -原因:1)malloc()作为 C 语言库对进程用户空间的管理和 2)操作系统对进程用户空间管理两级机制的问题了。C 语言库向操作系统申请可用的合法空间,并预留给变量或缓冲区来使用。然后用户进程通过 free()回收则代表这些区间不再用于原来的用途,但仍可能是合法空间(还能访问到原来该空间上的数据)。除非 C 语言库决定将某些内存区间向操作系统申请释放掉,这些区间才会称为非法空间。 -但是如果分配的空间较大,malloc()回收空间时会向操作系统申请释放相应的空间。 -* 屏显 5-7 Mem-malloc-8M 运行后的进程布局 -```bash -564c4c575000-564c4c596000 rw-p 00000000 00:00 0 [heap] -..... - -564c4c575000-564c4c596000 rw-p 00000000 00:00 0 [heap] -7fcd72fa8000-7fcd757ad000 rw-p 00000000 00:00 0 -...... - -564c4c575000-564c4c596000 rw-p 00000000 00:00 0 [heap] -7fcd72fa8000-7fcd737a9000 rw-p 00000000 00:00 0 -7fcd73faa000-7fcd747ab000 rw-p 00000000 00:00 0 -7fcd74fac000-7fcd757ad000 rw-p 00000000 00:00 0 -``` -* 表 5-1 /proc/PID/status 中关于 VM 的项 -```bash -# 初始状态 -VmPeak: 4504 kB -VmSize: 4504 kB -VmData: 176 kB -..... - -#分配 5 个 8MB 空间 -VmPeak: 45484 kB -VmSize: 45484 kB -VmData: 41156 kB -...... - -#释放 2 个 8MB -VmPeak: 45484 kB -VmSize: 29092 kB -VmData: 24764 kB -``` -VmSize:虚存总量 的变化——从少到多然后再下降 -VmPeak:记录着该进程历史上曾获得的最高虚存总量 -VmData:数据区 - -### 5.1.3 文件映射区 -mmap()可以完成内存映射文件的操作 -解除映射的函数为 munmap() -```c -#include -void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); -int munmap(void *start, size_t length); -``` -* 屏显 5-8 mmap-demo 的输出 -![image](./record/pic/5-8.png) -* 屏显 5-9 /proc/PID/maps 中的文件映射信息 -```bash -hypo@hypo-CW65S:$ ps -aux | grep mmap -hypo 3076 0.0 0.0 4508 740 pts/0 S+ 20:52 0:00 ./mmap-demo -hypo 3115 0.0 0.0 21532 1012 pts/1 S+ 20:53 0:00 grep --color=auto mmap -hypo@hypo-CW65S:$ cat /proc/3076/maps -..... -7f2c49815000-7f2c49816000 rw-s 00000000 08:01 615399 file-mapped.txt -...... -(hypo@hypo-CW65S:$ ls -i file-mapped.txt -615399 file-mapped.txt -``` -* 屏显 5-10 被修改后的 file-mmaped.txt 文件内容 -```bash -hypo@hypo-CW65S:$ cat file-mapped.txt -Modification in the memory---------e-mmapped buffer! -And this is the second line. -This is the last line! -``` - -### 5.1.4 栈区 -#### 主线程栈区 -每一次函数调用所扩展出来的堆栈空间被称为一个栈帧,因此随着函数的调用层次加深,堆栈的栈顶会随着栈帧的叠加而逐步扩展。函数调用时的返回地址、栈帧指针和函数内部的局部数据(也称堆栈变量、自动变量)都保存在堆栈中的某个栈帧结构上。 -* 屏显 5-11 stack-demo 运行输出 -![image](./record/pic/5-11.png) - -* 屏显 5-12 /proc/PID/maps 展示的堆栈变化 -```bash -#begin -7ffe5f0e5000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] -#第 1 层调用 -7ffe5f0c3000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] -#第 2层调用 -7ffe5f083000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] -#第 3层调用 -7ffe5f043000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] -#第 3层调用 -7ffe5f043000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] -#第 2层调用 -7ffe5f043000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] -#第 1 层调用 -7ffe5f043000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] -``` -#### 线程栈 -* 屏显 5-13 pthread-stack-demo 的运行结果 -![image](./record/pic/5-13.png) - -* 屏显 5-14 创建线程后的内存布局 -```bash -#线 程 创 建 前 -7ff695103000-7ff695104000 rw-p 00000000 00:00 0 -7ffd7f003000-7ffd7f024000 rw-p 00000000 00:00 0 [stack] -#线 程 创 建 后 -7ff695103000-7ff695104000 rw-p 00000000 00:00 0 -7ffd7f003000-7ffd7f024000 rw-p 00000000 00:00 0 [stack] -#在ubuntu18.04中并没有观察到出现两个stack -``` - -### 5.1.4 访问任意进程的虚存 -系统中有多个并发的进程存在,每个进程的虚存空间是独立的,除非映射了共享内存否则无法相互访问。进程通常只能通过/proc/self/mem 读取本进程内存的数据,但。 root 用户启动的进程可以不需要通过 ptrace 也能查看其他进程的内存空间,只要求被查看的进程处于不运行状态。 -* 屏显 5-15 /proc/PID/mem 访问权限 -![image](./record/pic/5-15.png) -* 屏显 5-16 show-var-addr 的输出 -![image](./record/pic/5-16.png) -* 屏显 5-17 read-proc-mem 的输出 -![image](./record/pic/5-17.png) -在16gb内存的ubuntu18.04操作系统下原代码运行失败,lseek64函数无法定位文件 - -### 5.1.6 虚存使用的物理页帧 - -```bash -cat /proc/PID/smaps #给出了 HelloWorld-gechar 进程各个虚存段使用物理页帧的情况 -``` -* 屏显 5-18 /proc/PID/smaps 的部分内容 -```bash -hypo@hypo-CW65S:$ cat /proc/19361/smaps -55a323dda000-55a323ddb000 r-xp 00000000 08:01 615382 HelloWorld-getchar -Size: 4 kB - -...... - -SwapPss: 0 kB -Locked: 0 kB -THPeligible: 0 -VmFlags: rd ex -``` - -### 5.2.1 分页机制 -1.每个处理器核上运行的进程使用的是虚地址,每次取指令或数据都需要将程序虚地址转换成物理地址,这需要借助于页表信息来转换. -### 5.2.2 进程页表 -* 屏显 5-19 show-virt-addr 的输出 -![image](./record/pic/5-19.png) -译后运行 show-virt-addr,打印出“Hello world!”字符串的虚地址 0x561a250f1754 -* 屏显 5-20 crash 启动信息 -```bash - - -``` - - - -# 课后作业 -#### 1.设计编写以下程序,着重考虑其通信和同步问题: - - -``` - -``` \ No newline at end of file diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/maps-check" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/maps-check" new file mode 100644 index 0000000000000000000000000000000000000000..8eead8578e0c7090087f2acd1dc339b67871297f --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/maps-check" @@ -0,0 +1,21 @@ +00400000-00401000 r-xp 00000000 fd:00 52072941 /home/hypo/linux-homework/5.内存管理/record/code/reclaim-swap-writeback-demo +00600000-00601000 r--p 00000000 fd:00 52072941 /home/hypo/linux-homework/5.内存管理/record/code/reclaim-swap-writeback-demo +00601000-00602000 rw-p 00001000 fd:00 52072941 /home/hypo/linux-homework/5.内存管理/record/code/reclaim-swap-writeback-demo +7fe7196da000-7fe7196df000 rw-p 00000000 00:00 0 +7fe7196df000-7fe71a6db000 rw-p 00000000 00:00 0 +7fe71a6db000-7fe71a6dd000 rw-s 00000000 fd:00 244 /home/hypo/tempfile +7fe71a6dd000-7fe71aedb000 rw-s 00002000 fd:00 244 /home/hypo/tempfile +7fe71aedb000-7fe71b09d000 r-xp 00000000 fd:00 364328 /usr/lib64/libc-2.17.so +7fe71b09d000-7fe71b29d000 ---p 001c2000 fd:00 364328 /usr/lib64/libc-2.17.so +7fe71b29d000-7fe71b2a1000 r--p 001c2000 fd:00 364328 /usr/lib64/libc-2.17.so +7fe71b2a1000-7fe71b2a3000 rw-p 001c6000 fd:00 364328 /usr/lib64/libc-2.17.so +7fe71b2a3000-7fe71b2a8000 rw-p 00000000 00:00 0 +7fe71b2a8000-7fe71b2ca000 r-xp 00000000 fd:00 2765112 /usr/lib64/ld-2.17.so +7fe71b4b1000-7fe71b4b4000 rw-p 00000000 00:00 0 +7fe71b4c7000-7fe71b4c9000 rw-p 00000000 00:00 0 +7fe71b4c9000-7fe71b4ca000 r--p 00021000 fd:00 2765112 /usr/lib64/ld-2.17.so +7fe71b4ca000-7fe71b4cb000 rw-p 00022000 fd:00 2765112 /usr/lib64/ld-2.17.so +7fe71b4cb000-7fe71b4cc000 rw-p 00000000 00:00 0 +7ffdd65ed000-7ffdd660e000 rw-p 00000000 00:00 0 [stack] +7ffdd664c000-7ffdd664e000 r-xp 00000000 00:00 0 [vdso] +ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/meminfo-check" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/meminfo-check" new file mode 100644 index 0000000000000000000000000000000000000000..95d3ad9f5c9a51233a4ff479a491db6895d9a00c --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/meminfo-check" @@ -0,0 +1,46 @@ +MemTotal: 1863248 kB +MemFree: 1151560 kB +MemAvailable: 1170196 kB +Buffers: 0 kB +Cached: 217140 kB +SwapCached: 90124 kB +Active: 137548 kB +Inactive: 340016 kB +Active(anon): 124936 kB +Inactive(anon): 218736 kB +Active(file): 12612 kB +Inactive(file): 121280 kB +Unevictable: 28 kB +Mlocked: 28 kB +SwapTotal: 2097148 kB +SwapFree: 1441364 kB +Dirty: 4 kB +Writeback: 0 kB +AnonPages: 200360 kB +Mapped: 107548 kB +Shmem: 83192 kB +Slab: 93800 kB +SReclaimable: 31668 kB +SUnreclaim: 62132 kB +KernelStack: 10192 kB +PageTables: 37436 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028772 kB +Committed_AS: 4616544 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 215276 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 32768 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 153472 kB +DirectMap2M: 1943552 kB +DirectMap1G: 0 kB diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/pages-blackhole-demo" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/pages-blackhole-demo" new file mode 100644 index 0000000000000000000000000000000000000000..1a308c3cbe3c768bb7a1875039421138fae5097b Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/pages-blackhole-demo" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/pages-blackhole-demo.c" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/pages-blackhole-demo.c" new file mode 100644 index 0000000000000000000000000000000000000000..cbda4269f12e937a16e252845acce601409fdb0f --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/pages-blackhole-demo.c" @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#define MB 1024*1024 +int main() +{ + int i,j; + char temp; + int fd= -1; + char * filemap_buf; + char * anon_buf; + anon_buf=(char *)malloc(2000*MB); + while(1) + { + for(i=0;i<2000*MB;i+=4096) + anon_buf[i]=0xaa; + sleep(1); + } + return 0; +} \ No newline at end of file diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/process-pages-demo" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/process-pages-demo" new file mode 100644 index 0000000000000000000000000000000000000000..3f3c0787a92742a4928b735fb6ba69a5aaccec8f Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/process-pages-demo" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/process-pages-demo.c" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/process-pages-demo.c" new file mode 100644 index 0000000000000000000000000000000000000000..da4f710362ae8220f2d8011ac4700d3b645643aa --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/process-pages-demo.c" @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#define MB 1024*1024 +#define KB 1024 +int main() +{ + int i,j; + char temp; + int fd= -1; + char * filemap_buf; + char * anon_buf; + printf("-----\n"); + getchar(); // checkpoint 1 initial state + + + //第二步将在进程初始布局之上,创建两个新的内存区间,一个是8MB 的文件映射,一个是16MB 的非文件映射(匿名)区间。 + if((fd=open("/home/hypo/tempfile",O_RDWR))<0) + printf("open tmpfile err!\n"); + if((filemap_buf=(char*)mmap(NULL,8*MB,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0))==MAP_FAILED) + printf("mmap fail!\n"); + anon_buf=(char *)malloc(16*MB); + printf("allocated/mmapped\n"); + printf("filemapped @ %p \n",filemap_buf); + printf("anon @ %p \n",anon_buf); + getchar(); // checkpoint 2 allocation + + //第三步将在上述进程布局之上,对文件映射区间的前4MB 和匿名区间的前8MB 进行读操作。 + for (i=0;i<4*MB;i+=4096) + temp=filemap_buf[i]; + for(i=0;i<8*MB;i+=4096) + temp=*(anon_buf+i); + printf("read finish\n "); + getchar(); // checkpoint 3 read finish + + //第四步在上述进程布局之上,对文件映射区间的前2MB 和匿名区间的前4MB 进行写操作 + for(i=0;i<2*MB;i+=4096) + filemap_buf[i]=temp; + for(i=0;i<4*MB;i+=4096) + anon_buf[i]=0xaa; + printf("write finish \n"); + getchar(); // checkpoint 4 write finish/make the pageframes dirty + + //最后将通过unmap()和free()释放文件映射区和匿名内存区。 + munmap(filemap_buf,8*MB); + free(anon_buf); + printf("all done \n"); + getchar(); // checkpoint 5 + return 0; +} \ No newline at end of file diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/reclaim-swap-writeback-demo" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/reclaim-swap-writeback-demo" new file mode 100644 index 0000000000000000000000000000000000000000..89e9e0076d9a4a1436fa5554b1de446df0f0cf46 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/reclaim-swap-writeback-demo" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/reclaim-swap-writeback-demo.c" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/reclaim-swap-writeback-demo.c" new file mode 100644 index 0000000000000000000000000000000000000000..9834a400157575be93b21f521180e8938f9efb9a --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/reclaim-swap-writeback-demo.c" @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#define MB 1024*1024 +#define KB 1024 +int main() +{ + int i,pid; + char temp; + int fd= -1; + char *filemap_buf; + char command_smaps[100]; + char command_status[100]; + char command_meminfo[100]; + char command_maps[100]; + char * anon_buf; + pid=getpid(); + sprintf(command_smaps,"cat /proc/%d/smaps > smaps-check",pid); + sprintf(command_status,"cat /proc/%d/status > status-check",pid); + sprintf(command_meminfo,"cat /proc/meminfo >meminfo-check"); + sprintf(command_maps,"cat /proc/%d/maps >maps-check",pid); + + //在进程初始布局之上,创建两个新的内存区间,一个是8MB 的文件映射,一个是16MB 的非文件映射(匿名)区间。各自用mlock()函数锁定8KB 和16KB 的空间(不可换出) + if((fd=open("/home/hypo/tempfile",O_RDWR))<0) + printf("open tmpfile err!\n"); + if((filemap_buf=(char *) mmap(NULL, 8*MB, PROT_READ|PROT_WRITE, MAP_SHARED,fd,0)) ==MAP_FAILED ) + printf("mmap fail!\n"); + mlock(filemap_buf,8*KB); + anon_buf=(char *)malloc(16*MB); + mlock(anon_buf,16*KB); + printf("allocated/mmapped\n"); + printf("filemapped @ %p \n",filemap_buf); + printf("anon @ %p \n",anon_buf); + system(command_maps); + system(command_smaps); + system(command_status); + system(command_meminfo); + getchar(); // checkpoint 1 allocation + + //对文件映射区间的前4MB 和匿名区间的前8MB 进行读和写操作各一遍。 + for(i=0;i<4*MB;i+=4096) + filemap_buf[i]=temp; + for(i=0;i<8*MB;i+=4096) + anon_buf[i]=0xaa; + printf("write finish \n"); + system(command_smaps); + system(command_status); + system(command_meminfo); + getchar(); // checkpoint 2 write finish/make the pageframes dirty + + //run pages-blackhole-demo.c + //该pagesblackhole-demo 进程将大量消耗物理页帧,因此会引起reclaim-swap-writeback-demo进程的页帧被回收 + printf("please run pages-blackhole-demo\n"); + getchar(); // checkpoint 3 be swapped out + system(command_smaps); + system(command_status); + system(command_meminfo); + getchar(); + + //最后将通过对文件映射区间的前4MB 和匿名区间的前8MB 进行反复的读写操作。可以检查该进程重新获得物理页帧的现象。 + printf("compete for the page frames\n"); + while(1) //compete for the page frames, by writing + { + for(i=0;i<1*MB;i+=4096) + filemap_buf[i]=temp; + for(i=0;i<2*MB;i+=4096) + anon_buf[i]=0xaa; + } + getchar(); // checkpoint 4 will never get to this point + + munmap(filemap_buf,8*MB); + free(anon_buf); + return 0; +} \ No newline at end of file diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/show-virt-addr" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/show-virt-addr" index e8e8f4f230f00c27cbd3447be5b3425540eebb4b..0b45ae5fd04211a8590c30997da3214717921a1d 100644 Binary files "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/show-virt-addr" and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/show-virt-addr" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/smaps-check" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/smaps-check" new file mode 100644 index 0000000000000000000000000000000000000000..c48f69c5e6106ad4fdd934e5fe2d19b33340078f --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/smaps-check" @@ -0,0 +1,357 @@ +00400000-00401000 r-xp 00000000 fd:00 52072941 /home/hypo/linux-homework/5.内存管理/record/code/reclaim-swap-writeback-demo +Size: 4 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 4 kB +Private_Dirty: 0 kB +Referenced: 4 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd ex mr mp me dw sd +00600000-00601000 r--p 00000000 fd:00 52072941 /home/hypo/linux-homework/5.内存管理/record/code/reclaim-swap-writeback-demo +Size: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 4 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd mr mp me dw ac sd +00601000-00602000 rw-p 00001000 fd:00 52072941 /home/hypo/linux-homework/5.内存管理/record/code/reclaim-swap-writeback-demo +Size: 4 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 4 kB +Private_Dirty: 0 kB +Referenced: 4 kB +Anonymous: 4 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me dw ac sd +7fe7196da000-7fe7196df000 rw-p 00000000 00:00 0 +Size: 20 kB +Rss: 20 kB +Pss: 20 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 20 kB +Referenced: 20 kB +Anonymous: 20 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 20 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me lo ac sd +7fe7196df000-7fe71a6db000 rw-p 00000000 00:00 0 +Size: 16368 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 9348 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7fe71a6db000-7fe71a6dd000 rw-s 00000000 fd:00 244 /home/hypo/tempfile +Size: 8 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 8 kB +Private_Dirty: 0 kB +Referenced: 8 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 8 kB +ProtectionKey: 0 +VmFlags: rd wr sh mr mp me ms lo sd +7fe71a6dd000-7fe71aedb000 rw-s 00002000 fd:00 244 /home/hypo/tempfile +Size: 8184 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr sh mr mp me ms sd +7fe71aedb000-7fe71b09d000 r-xp 00000000 fd:00 364328 /usr/lib64/libc-2.17.so +Size: 1800 kB +Rss: 48 kB +Pss: 9 kB +Shared_Clean: 40 kB +Shared_Dirty: 0 kB +Private_Clean: 8 kB +Private_Dirty: 0 kB +Referenced: 48 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd ex mr mp me sd +7fe71b09d000-7fe71b29d000 ---p 001c2000 fd:00 364328 /usr/lib64/libc-2.17.so +Size: 2048 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: mr mp me sd +7fe71b29d000-7fe71b2a1000 r--p 001c2000 fd:00 364328 /usr/lib64/libc-2.17.so +Size: 16 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 16 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd mr mp me ac sd +7fe71b2a1000-7fe71b2a3000 rw-p 001c6000 fd:00 364328 /usr/lib64/libc-2.17.so +Size: 8 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4 kB +Referenced: 4 kB +Anonymous: 4 kB +AnonHugePages: 0 kB +Swap: 4 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7fe71b2a3000-7fe71b2a8000 rw-p 00000000 00:00 0 +Size: 20 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 4 kB +Private_Dirty: 4 kB +Referenced: 8 kB +Anonymous: 8 kB +AnonHugePages: 0 kB +Swap: 4 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7fe71b2a8000-7fe71b2ca000 r-xp 00000000 fd:00 2765112 /usr/lib64/ld-2.17.so +Size: 136 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd ex mr mp me dw sd +7fe71b4b1000-7fe71b4b4000 rw-p 00000000 00:00 0 +Size: 12 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 12 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7fe71b4c6000-7fe71b4c9000 rw-p 00000000 00:00 0 +Size: 12 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4 kB +Referenced: 4 kB +Anonymous: 4 kB +AnonHugePages: 0 kB +Swap: 8 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7fe71b4c9000-7fe71b4ca000 r--p 00021000 fd:00 2765112 /usr/lib64/ld-2.17.so +Size: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 4 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd mr mp me dw ac sd +7fe71b4ca000-7fe71b4cb000 rw-p 00022000 fd:00 2765112 /usr/lib64/ld-2.17.so +Size: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 4 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me dw ac sd +7fe71b4cb000-7fe71b4cc000 rw-p 00000000 00:00 0 +Size: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 4 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7ffdd65ed000-7ffdd660e000 rw-p 00000000 00:00 0 [stack] +Size: 132 kB +Rss: 12 kB +Pss: 12 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 4 kB +Private_Dirty: 8 kB +Referenced: 12 kB +Anonymous: 12 kB +AnonHugePages: 0 kB +Swap: 4 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me gd ac +7ffdd664c000-7ffdd664e000 r-xp 00000000 00:00 0 [vdso] +Size: 8 kB +Rss: 4 kB +Pss: 0 kB +Shared_Clean: 4 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 4 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd ex mr mp me de sd +ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] +Size: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd ex diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/status-check" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/status-check" new file mode 100644 index 0000000000000000000000000000000000000000..f296f1d25494aaf2225e9b96b11c891913d0f07c --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/code/status-check" @@ -0,0 +1,47 @@ +Name: reclaim-swap-wr +Umask: 0002 +State: S (sleeping) +Tgid: 9093 +Ngid: 0 +Pid: 9093 +PPid: 8915 +TracerPid: 0 +Uid: 1000 1000 1000 1000 +Gid: 1000 1000 1000 1000 +FDSize: 256 +Groups: 1000 +VmPeak: 28796 kB +VmSize: 28796 kB +VmLck: 28 kB +VmPin: 0 kB +VmHWM: 13996 kB +VmRSS: 56 kB +RssAnon: 24 kB +RssFile: 32 kB +RssShmem: 0 kB +VmData: 16444 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 60 kB +VmSwap: 9440 kB +Threads: 1 +SigQ: 0/7144 +SigPnd: 0000000000000000 +ShdPnd: 0000000000000000 +SigBlk: 0000000000010000 +SigIgn: 0000000000000006 +SigCgt: 0000000000000000 +CapInh: 0000000000000000 +CapPrm: 0000000000000000 +CapEff: 0000000000000000 +CapBnd: 0000001fffffffff +CapAmb: 0000000000000000 +Seccomp: 0 +Speculation_Store_Bypass: thread vulnerable +Cpus_allowed: ffffffff,ffffffff,ffffffff,ffffffff +Cpus_allowed_list: 0-127 +Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001 +Mems_allowed_list: 0 +voluntary_ctxt_switches: 17 +nonvoluntary_ctxt_switches: 2 diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-19.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-19.png" index 2c24f44375f76150f0e121f451230cfddba38cb2..2a2f481f51f1bfcf466ef5aeefaa257898b8888a 100644 Binary files "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-19.png" and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-19.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-21.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-21.png" new file mode 100644 index 0000000000000000000000000000000000000000..d3e638a90b3fada54ca0caad8679fd03c6d3e5b6 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-21.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-22.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-22.png" new file mode 100644 index 0000000000000000000000000000000000000000..3c1ad7ca9a4ebcd725cdb418088f16b23b632ccd Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-22.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-23.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-23.png" new file mode 100644 index 0000000000000000000000000000000000000000..ec2e8f1394be31c99708145de12b5fae680d0408 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-23.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-28.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-28.png" new file mode 100644 index 0000000000000000000000000000000000000000..342b1a63b6a44593d925357587d0cfb0ae092d9b Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-28.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-30.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-30.png" new file mode 100644 index 0000000000000000000000000000000000000000..4c1567d1c75780bbb055cc9761ac552e3a72b4a8 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/5-30.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/biao5-6.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/biao5-6.png" new file mode 100644 index 0000000000000000000000000000000000000000..7461b361e214d9649666d133df5d293d491c22f5 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/biao5-6.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/pic5-11.png" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/pic5-11.png" new file mode 100644 index 0000000000000000000000000000000000000000..a9d3941e5604302642d847729f3b61250fb3ded6 Binary files /dev/null and "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/record/pic/pic5-11.png" differ diff --git "a/5.\345\206\205\345\255\230\347\256\241\347\220\206/report.md" "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/report.md" new file mode 100644 index 0000000000000000000000000000000000000000..a3b45158eb54ef8e3b83321ef44e4edfcb95ae57 --- /dev/null +++ "b/5.\345\206\205\345\255\230\347\256\241\347\220\206/report.md" @@ -0,0 +1,1746 @@ +[toc] +## 实验目的 +* 通过编程实践、观察,学习内存管理的方式。 +## 实验环境 +* 硬件 +1.Intel(R) Xeon(R) Bronze 3104 CPU @ 1.70GHz +2.DDR4 16G +* 软件 +1.CentOS 7 +2.ubuntu 18.04 +3.VMware Workstation Pro 15 +## 实验记录 +### 5.1.1 进程映像 +* 屏显 5-1 HelloWorld-getchar 的内存布局 +![image](./record/pic/5-1.png) +每一行是一个具有特定属性的连续的内存区,每行的开头是该区间的地址范围。后面的 rxwp 分别代表:r=可读、w=可写、x=可执行、s=共享以及 p=私有,再后面一列的数字用于表示文件映射内存对应于文件中的起始位置(如果不是文件映射区则为 0)。 +* 屏显 5-2 ELF 可执行文件的节 +```bash +(base) hypo@hypo-CW65S$ readelf -S HelloWorld-getchar +There are 29 section headers, starting at offset 0x1968: +节头: + [号] 名称 类型 地址 偏移量 + 大小 全体大小 旗标 链接 信息 对齐 + [ 0] NULL 0000000000000000 00000000 + 0000000000000000 0000000000000000 0 0 0 +...... + [14] .text PROGBITS 0000000000000580 00000580 + 00000000000001a2 0000000000000000 AX 0 0 16 + [16] .rodata PROGBITS 0000000000000730 00000730 + 0000000000000010 0000000000000000 A 0 0 4 +...... + [23] .data PROGBITS 0000000000201000 00001000 + 0000000000000010 0000000000000000 WA 0 0 8 + [24] .bss NOBITS 0000000000201010 00001010 + 0000000000000008 0000000000000000 WA 0 0 1 +...... +Key to Flags: + W (write), A (alloc), X (execute), M (merge), S (strings), I (info), + L (link order), O (extra OS processing required), G (group), T (TLS), + C (compressed), x (unknown), o (OS specific), E (exclude), + l (large), p (processor specific) +``` +1.其中编号为 13 的.text 节是 Helloworld-getchar.c 编译后的 x86-64 平台上的可执行二进制代码 +2.编号为 23 的.data是用于保存已初始化的全局变量和局部静态变量 +3.编号为 16 的.rodata 是编译器识别出来的只读数据 + +* 屏显 5-3 ELF 段以及段-节映射关系 + ELF 可执行文件的程序头(Program Header)里面描述了与装入过程有关的信息,告知操作系统如何将它们映射到虚拟空间中。我们用 readelf -l 命令查看这些信息 + ![image](./record/pic/5-3.png) + 02 段所对应的节装入到虚存空间VirtAddr=0x0000000000000000 的区域中,而且此虚存空间区域的属性需要设置为“R E”——表示只读和可执行(包括了代码段和只读数据)。 +03 段所对应的节装入到虚存空间VirtAddr=0x0000000000200db0 的区域内,并且其属性 Flags 为“RW”表示可读可写,但不可执行(因为它们都是数据) + +### 5.1.2 堆区 +在堆区分配内存可以用 malloc()等函数来完成,用完后需要用 free()进行释放。malloc()函数的原型如下: +```c +#include +void *malloc(unsigned int num_bytes); +``` +该函数将分配长度为 num_bytes 字节的内存块,如果分配成功则返回指向被分配内存的指针,否则返回空指针 NULL。当内存不再使用时,应使用 free()函数将内存块释放。 +* 屏显 5-4 执行 malloc()之前的内存布局 +![image](./record/pic/5-4.png) +* 屏显 5-5 执行 5 次 malloc()之后的内存布局 +![image](./record/pic/5-5.png) +* 屏显 5-6 执行 2 次 free()之后的内存布局 +![image](./record/pic/5-6.png) +观察[heap]区,由于将 5 次分配的内存释放掉第 2/4 次分配的空间,原来的空间将被分割成多段,但是 Linux 操作系统似乎并没有将这两段区间回收。 +原因:1)malloc()作为 C 语言库对进程用户空间的管理和 2)操作系统对进程用户空间管理两级机制的问题了。C 语言库向操作系统申请可用的合法空间,并预留给变量或缓冲区来使用。然后用户进程通过 free()回收则代表这些区间不再用于原来的用途,但仍可能是合法空间(还能访问到原来该空间上的数据)。除非 C 语言库决定将某些内存区间向操作系统申请释放掉,这些区间才会称为非法空间。 +但是如果分配的空间较大,malloc()回收空间时会向操作系统申请释放相应的空间。 +* 屏显 5-7 Mem-malloc-8M 运行后的进程布局 +```bash +564c4c575000-564c4c596000 rw-p 00000000 00:00 0 [heap] +..... + +564c4c575000-564c4c596000 rw-p 00000000 00:00 0 [heap] +7fcd72fa8000-7fcd757ad000 rw-p 00000000 00:00 0 +...... + +564c4c575000-564c4c596000 rw-p 00000000 00:00 0 [heap] +7fcd72fa8000-7fcd737a9000 rw-p 00000000 00:00 0 +7fcd73faa000-7fcd747ab000 rw-p 00000000 00:00 0 +7fcd74fac000-7fcd757ad000 rw-p 00000000 00:00 0 +``` +* 表 5-1 /proc/PID/status 中关于 VM 的项 +```bash +# 初始状态 +VmPeak: 4504 kB +VmSize: 4504 kB +VmData: 176 kB +..... + +#分配 5 个 8MB 空间 +VmPeak: 45484 kB +VmSize: 45484 kB +VmData: 41156 kB +...... + +#释放 2 个 8MB +VmPeak: 45484 kB +VmSize: 29092 kB +VmData: 24764 kB +``` +VmSize:虚存总量 的变化——从少到多然后再下降 +VmPeak:记录着该进程历史上曾获得的最高虚存总量 +VmData:数据区 + +### 5.1.3 文件映射区 +mmap()可以完成内存映射文件的操作 +解除映射的函数为 munmap() +```c +#include +void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); +int munmap(void *start, size_t length); +``` +* 屏显 5-8 mmap-demo 的输出 +![image](./record/pic/5-8.png) +* 屏显 5-9 /proc/PID/maps 中的文件映射信息 +```bash +hypo@hypo-CW65S:$ ps -aux | grep mmap +hypo 3076 0.0 0.0 4508 740 pts/0 S+ 20:52 0:00 ./mmap-demo +hypo 3115 0.0 0.0 21532 1012 pts/1 S+ 20:53 0:00 grep --color=auto mmap +hypo@hypo-CW65S:$ cat /proc/3076/maps +..... +7f2c49815000-7f2c49816000 rw-s 00000000 08:01 615399 file-mapped.txt +...... +(hypo@hypo-CW65S:$ ls -i file-mapped.txt +615399 file-mapped.txt +``` +* 屏显 5-10 被修改后的 file-mmaped.txt 文件内容 +```bash +hypo@hypo-CW65S:$ cat file-mapped.txt +Modification in the memory---------e-mmapped buffer! +And this is the second line. +This is the last line! +``` + +### 5.1.4 栈区 +#### 主线程栈区 +每一次函数调用所扩展出来的堆栈空间被称为一个栈帧,因此随着函数的调用层次加深,堆栈的栈顶会随着栈帧的叠加而逐步扩展。函数调用时的返回地址、栈帧指针和函数内部的局部数据(也称堆栈变量、自动变量)都保存在堆栈中的某个栈帧结构上。 +* 屏显 5-11 stack-demo 运行输出 +![image](./record/pic/5-11.png) + +* 屏显 5-12 /proc/PID/maps 展示的堆栈变化 +```bash +#begin +7ffe5f0e5000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] +#第 1 层调用 +7ffe5f0c3000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] +#第 2层调用 +7ffe5f083000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] +#第 3层调用 +7ffe5f043000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] +#第 3层调用 +7ffe5f043000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] +#第 2层调用 +7ffe5f043000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] +#第 1 层调用 +7ffe5f043000-7ffe5f106000 rw-p 00000000 00:00 0 [stack] +``` +#### 线程栈 +* 屏显 5-13 pthread-stack-demo 的运行结果 +![image](./record/pic/5-13.png) + +* 屏显 5-14 创建线程后的内存布局 +```bash +#线 程 创 建 前 +7ff695103000-7ff695104000 rw-p 00000000 00:00 0 +7ffd7f003000-7ffd7f024000 rw-p 00000000 00:00 0 [stack] +#线 程 创 建 后 +7ff695103000-7ff695104000 rw-p 00000000 00:00 0 +7ffd7f003000-7ffd7f024000 rw-p 00000000 00:00 0 [stack] +#在ubuntu18.04中并没有观察到出现两个stack +``` + +### 5.1.4 访问任意进程的虚存 +系统中有多个并发的进程存在,每个进程的虚存空间是独立的,除非映射了共享内存否则无法相互访问。进程通常只能通过/proc/self/mem 读取本进程内存的数据,但。 root 用户启动的进程可以不需要通过 ptrace 也能查看其他进程的内存空间,只要求被查看的进程处于不运行状态。 +* 屏显 5-15 /proc/PID/mem 访问权限 +![image](./record/pic/5-15.png) +* 屏显 5-16 show-var-addr 的输出 +![image](./record/pic/5-16.png) +* 屏显 5-17 read-proc-mem 的输出 +![image](./record/pic/5-17.png) +在16gb内存的ubuntu18.04操作系统下原代码运行失败,lseek64函数无法定位文件 + +### 5.1.6 虚存使用的物理页帧 + +```bash +cat /proc/PID/smaps #给出了 HelloWorld-gechar 进程各个虚存段使用物理页帧的情况 +``` +* 屏显 5-18 /proc/PID/smaps 的部分内容 +```bash +hypo@hypo-CW65S:$ cat /proc/19361/smaps +55a323dda000-55a323ddb000 r-xp 00000000 08:01 615382 HelloWorld-getchar +Size: 4 kB + +...... + +SwapPss: 0 kB +Locked: 0 kB +THPeligible: 0 +VmFlags: rd ex +``` + +### 5.2.1 分页机制 +1.每个处理器核上运行的进程使用的是虚地址,每次取指令或数据都需要将程序虚地址转换成物理地址,这需要借助于页表信息来转换. + +### 5.2.2 进程页表 +由于ubuntu下无法安装kernel-debuginfo,下面的内容将在CentOS7中实现 +* 屏显 5-19 show-virt-addr 的输出 +```bash +[hypo@localhost code]$ ./show-virt-addr +Hello world! + @ 0x400630 +``` +![image](./record/pic/5-19.png) + +译后运行 show-virt-addr,打印出“Hello world!”字符串的虚地址 0x561a250f1754 +* 屏显 5-20 crash 启动信息 + +```bash +[root@localhost code]# crash + +crash 7.2.3-8.el7 +Copyright (C) 2002-2017 Red Hat, Inc. +Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation +Copyright (C) 1999-2006 Hewlett-Packard Co +Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited +Copyright (C) 2006, 2007 VA Linux Systems Japan K.K. +Copyright (C) 2005, 2011 NEC Corporation +Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc. +Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +This program is free software, covered by the GNU General Public License, +and you are welcome to change it and/or distribute copies of it under +certain conditions. Enter "help copying" to see the conditions. +This program has absolutely no warranty. Enter "help warranty" for details. + +GNU gdb (GDB) 7.6 +Copyright (C) 2013 Free Software Foundation, Inc. +License GPLv3+: GNU GPL version 3 or later +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. Type "show copying" +and "show warranty" for details. +This GDB was configured as "x86_64-unknown-linux-gnu"... + +WARNING: kernel relocated [892MB]: patching 85605 gdb minimal_symbol values + + KERNEL: /usr/lib/debug/lib/modules/3.10.0-957.el7.x86_64/vmlinux + DUMPFILE: /dev/crash + CPUS: 4 + DATE: Wed Nov 20 16:06:12 2019 + UPTIME: 01:13:52 +LOAD AVERAGE: 0.15, 0.12, 0.17 + TASKS: 558 + NODENAME: localhost.localdomain + RELEASE: 3.10.0-957.el7.x86_64 + VERSION: #1 SMP Thu Nov 8 23:39:32 UTC 2018 + MACHINE: x86_64 (2501 Mhz) + MEMORY: 2 GB + PID: 13115 + COMMAND: "crash" + TASK: ffff98a87ea2a080 [THREAD_INFO: ffff98a84dd18000] + CPU: 3 + STATE: TASK_RUNNING (ACTIVE) + +crash> + +``` +* 屏显 5-21 执行set 命令 +```bash +crash> set 9301 + PID: 9301 +COMMAND: "show-virt-addr" + TASK: ffff9c8597f50000 [THREAD_INFO: ffff9c859472c000] + CPU: 0 + STATE: TASK_INTERRUPTIBLE +``` +![image](./record/pic/5-21.png) +show-virt-addr 进程的PCB(task_struct)地址为0xffff9c8597f50000 +* 屏显 5-22 用px 命令查看task_struct->mm->pgd 页表起始地址 +```bash +crash> px ((struct task_struct *)0xffff9c8597f50000)->mm->pgd +$1 = (pgd_t *) 0xffff9c858ec60000 #PGD 起点的虚地址处 +``` +![image](./record/pic/5-22.png) +可以看出页表起始地址位于0xffff9c858ec60000 的虚地址处 + +* 地址变换过程 +在使用页表进行地址转换前,我们先对虚地址进行分析,然后再展示地址转换原理。由于本例是使用64 位系统,一个页4KB 只能保存512 项页表项(4096 字节/8 字节=512),虚拟地址菜用4 级分页(9bit + 9bit + 9bit + 9bit + 12bit)——对应于PGD 索引/偏移、PUD 索引/偏移、PMD 索引/偏移、PD 索引/偏移和页内偏移. +![image](./record/pic/pic5-11.png) +```bash +#各级索引/偏移值的计算过程如下: +1.PGD 中的索引/偏移: (0x400630)>>(9+ 9 + 9 + 12)) & 0x1ff = 0 +2.PUD 中的索引/偏移: (0x400630)>>(9 + 9 + 12)) & 0x1ff = 0 +3.PMD 中的索引/偏移: (0x400630)>>(9 + 12)) & 0x1ff = 0x2 +4.PTE 中的索引/偏移: (0x400630)>>(12)) & 0x1ff = 0 +``` +* 屏显 5-23 PGD 第0 项的读入 +```bash +crash> px (0xffff9c858ec60000-0xffff880000000000) +$2 = 0x14858ec60000 #PGD 起点的物理地址 +crash> rd 0xffff9c858ec60000 +ffff9c858ec60000: 8000000017e7b067 g....... +crash> pte 8000000017e7b067 #用pte 命令对其解释也获得相同的物理页帧号 + PTE PHYSICAL FLAGS +8000000017e7b067 17e7b000 (PRESENT|RW|USER|ACCESSED|DIRTY|NX) +#px命令无法获得期望的结果 +``` +![image](./record/pic/5-23.png) + +* 屏显 5-24 PUD 第0 项的读入 +```bash +crash> rd -p 0x17e7b000 + 17e7b000: 000000001e687067 gph..... +``` +获得PMD 的地址(物理页帧号0x1e687) +虚地址0x1e687067 在PMG 的索引/偏移量为0x02(相当于16 字节),因此用物理地址方式读入rd -p 0x1e687010 +* 屏显 5-25 PMD 第0x2 项的读入 +```bash +crash> rd -p 0x1e687010 + 1e687010: 0000000017f40067 g....... +``` +此时获得物理页帧位于物理地址0x17f40000处 +*屏显 5-26 PTE 第0 项的读入 +```bash +crash> rd -p 0x17f40000 + 17f40000: 000000001a6e1005 ........ +crash> pte 000000001a6e1005 +PTE PHYSICAL FLAGS +1a6e1005 1a6e1000 (PRESENT|USER) +``` +* 屏显 5-27 读入物理地址的内容 +```bash +crash> rd -p 1a6e1630 2 +1a6e1630: 6f77206f6c6c6548 7325000a21646c72 Hello world!..%s +``` +### 5.3.1 页帧、节点、内存域 +* 物理页帧 +物理内存的分配使用、访问权限保护等管理都是以页帧为单位进行的。一个物理页帧的大小和一个虚存页的大小相等.进程用户空间使用的页帧根据是否被改写分为dirty 脏页和clean 干净页。干净的匿名页内容为全0,改写后变为脏页。如果需要回收改写后的匿名页帧,则需要将其内容换出到交换空间。干净的文件映射页(页缓存中的页)内容来自于文件的对应内容,改写后变为脏页。如果需要回收脏文件映射页,则通过回写重新变为干净页而可以另作他用。当进程修改了文件映射页里的数据时,该页就被内核标记为脏页,与磁盘数据产生不一致。内核将会在合适的时间把脏页的数据写到磁盘中去,以保持内存中的数据和磁盘中的数据是一致的,该操作称为文件同步操作。 + +*NUMA 与UMA +UMA 架构中只有一个节点,各个处理器核访问同一物理地址单元时是完全对等的,而NUMA 架构中,不同处理器核在访问同一内存区域时却可能会有速度上的差异。 + +* 屏显 5-28 一个UMA 系统上的/proc/zoneinfo +![image](./record/pic/5-28.png) +```bash +Node 0, zone DMA #DMA + pages free 2053 + min 96 + low 120 + high 144 + scanned 0 + spanned 4095 + present 3997 + managed 3976 +...... + + inactive_ratio: 1 +Node 0, zone DMA32 #这里开始时DMA32 的ZONE + pages free 47254 + +...... + + all_unreclaimable: 0 + start_pfn: 4096 #zone DMA32 的第一个物理页帧号是4096 + inactive_ratio: 3 + +``` +可以看出该系统只有1 个节点——node0,但是里面划分为两个内存域DMA 和DMA32——DMA 内存域从1 号页帧开始而DMA32 内存域从4096 号页帧开始。 + +### 5.3.2 空闲页帧管理——Buddy 系统 +每个内存域中未使用的空闲页帧,都由zone-> free_area[]组织成多个链表,并由buddy 系统管理。 + +* 代码 5-9 free_arae (linux-3.13/include/linux/mmzone.h) +```c +struct free_area { +struct list_head free_list[MIGRATE_TYPES]; +unsigned long nr_free; +}; +//其中nr_free 是对当前链表上所有空闲页帧的计数。MIGRATE_TYPES 是页帧的迁移属性 +``` + +* 屏显 5-30 UMA 系统上的buddy 信息 +![image](./record/pic/5-28.png) + +* 屏显 5-32 /proc/pagetypeinfo 中关于页帧迁移属性的信息 +``` +[hypo@localhost code]$ cat /proc/pagetypeinfo +Page block order: 9 +Pages per block: 512 + +Free pages count per migrate type at order 0 1 2 3 4 5 6 7 8 9 10 +Node 0, zone DMA, type Unmovable 2 4 5 0 2 2 0 1 1 1 0 +Node 0, zone DMA, type Reclaimable 0 3 0 3 0 0 0 1 1 0 0 +Node 0, zone DMA, type Movable 5 1 0 1 1 1 1 1 1 0 0 +Node 0, zone DMA, type Reserve 0 0 0 0 0 0 0 0 0 0 0 +Node 0, zone DMA, type CMA 0 0 0 0 0 0 0 0 0 0 0 +Node 0, zone DMA, type Isolate 0 0 0 0 0 0 0 0 0 0 0 +Node 0, zone DMA32, type Unmovable 140 80 40 45 18 7 1 1 1 0 0 +Node 0, zone DMA32, type Reclaimable 1 55 23 35 6 2 1 0 0 0 0 +Node 0, zone DMA32, type Movable 24 146 1715 727 536 251 98 30 56 1 0 +Node 0, zone DMA32, type Reserve 0 0 0 0 0 0 0 0 0 0 0 +Node 0, zone DMA32, type CMA 0 0 0 0 0 0 0 0 0 0 0 +Node 0, zone DMA32, type Isolate 0 0 0 0 0 0 0 0 0 0 0 + +Number of blocks type Unmovable Reclaimable Movable Reserve CMA Isolate +Node 0, zone DMA 3 1 4 0 0 0 +Node 0, zone DMA32 110 20 886 0 0 0 + +``` +### 5.3.3 物理内存分配与回收 +Linux 在/proc/meminfo 中记录了系统中全部物理页帧的使用情况 +* 屏显 5-33 /proc/meminfo 信息 +```bash +[hypo@localhost code]$ cat /proc/meminfo +MemTotal: 1863224 kB +MemFree: 218968 kB +MemAvailable: 481060 kB +Buffers: 0 kB +Cached: 593472 kB +SwapCached: 676 kB +Active: 866552 kB +Inactive: 519076 kB +Active(anon): 677668 kB +Inactive(anon): 334056 kB +Active(file): 188884 kB +Inactive(file): 185020 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 2097148 kB +SwapFree: 2091252 kB +Dirty: 16 kB +Writeback: 0 kB +AnonPages: 791500 kB +Mapped: 342916 kB +Shmem: 219568 kB +Slab: 98952 kB +SReclaimable: 38556 kB +SUnreclaim: 60396 kB +KernelStack: 9984 kB +PageTables: 37444 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028760 kB +Committed_AS: 4615408 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 215280 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 251904 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 135040 kB +DirectMap2M: 1961984 kB +DirectMap1G: 0 kB + +``` +* 屏显 5-34 free 命令的输出 +```bash +#简单地了解系统中的页帧使用情况则可以用free命令 +#第一行是物理内存使用统计量,分别是总量、已使用量、空闲量、用于共享内存的量、用于缓存的量以及可用的量 +#另一行是交换空间的使用量 +[hypo@localhost code]$ free + total used free shared buff/cache available +Mem: 1863224 952416 217520 220476 693288 479616 +Swap: 2097148 5896 2091252 +``` + +* 进程的页帧使用 +```bash +#创建用于映射的文件 +[hypo@localhost ~]$ dd if=/dev/zero of=/home/hypo/tempfile bs=1024 count=8192 +8192+0 records in +8192+0 records out +8388608 bytes (8.4 MB) copied, 0.0679351 s, 123 MB/s +#代码 5-10 process-pages-demo.c 代码 运行情况 +``` +* 屏显 5-35 porcess-pages-demo 的内存布局 +```bash +[hypo@localhost ~]$ cat /proc/9191/maps +...... +7f19df573000-7f19e0574000 rw-p 00000000 00:00 0 +7f19e0574000-7f19e0d74000 rw-s 00000000 fd:00 472929 /home/hypo/tempfile +...... +``` + +* 表 5-3 /proc/PID/smaps 在各检查点上的数值 +```bash +# checkpoint 1 +# NONE +# checkpoint 2 +7f19df573000-7f19e0574000 rw-p 00000000 00:00 0 +Size: 16388 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4 kB +Referenced: 4 kB +Anonymous: 4 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +7f19e0574000-7f19e0d74000 rw-s 00000000 fd:00 472929 +Size: 8192 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +# checkpoint 3 +7f19df573000-7f19e0574000 rw-p 00000000 00:00 0 +Size: 16388 kB +Rss: 4 kB +Pss: 4 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4 kB +Referenced: 4 kB +Anonymous: 4 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7f19e0574000-7f19e0d74000 rw-s 00000000 fd:00 472929 /home/hypo/tempfile +Size: 8192 kB +Rss: 4096 kB +Pss: 4096 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 4096 kB +Private_Dirty: 0 kB +Referenced: 4096 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr sh mr mp me ms sd +# checkpoint 4 +7f19df573000-7f19e0574000 rw-p 00000000 00:00 0 +Size: 16388 kB +Rss: 4660 kB +Pss: 4660 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4660 kB +Referenced: 4660 kB +Anonymous: 4660 kB +AnonHugePages: 4096 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7f19e0574000-7f19e0d74000 rw-s 00000000 fd:00 472929 /home/hypo/tempfile +Size: 8192 kB +Rss: 4096 kB +Pss: 4096 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 2048 kB +Private_Dirty: 2048 kB +Referenced: 4096 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr sh mr mp me ms sd +# checkpoint 5 +#None +``` + +* 表 5-4 /proc/PID/status 在各检查点上的数值 +```bash +# checkpoint 1 +VmPeak: 4288 kB +VmSize: 4216 kB +VmLck: 0 kB +VmPin: 0 kB +VmHWM: 352 kB +VmRSS: 352 kB +RssAnon: 76 kB +RssFile: 276 kB +RssShmem: 0 kB +VmData: 56 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 28 kB +VmSwap: 0 kB +# checkpoint 2 +VmPeak: 28796 kB +VmSize: 28796 kB +VmLck: 0 kB +VmPin: 0 kB +VmHWM: 352 kB +VmRSS: 352 kB +RssAnon: 76 kB +RssFile: 276 kB +RssShmem: 0 kB +VmData: 16444 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 32 kB +VmSwap: 0 kB +# checkpoint 3 +VmPeak: 28796 kB +VmSize: 28796 kB +VmLck: 0 kB +VmPin: 0 kB +VmHWM: 4604 kB +VmRSS: 4604 kB +RssAnon: 100 kB +RssFile: 4504 kB +RssShmem: 0 kB +VmData: 16444 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 60 kB +VmSwap: 0 kB +# checkpoint 4 +VmPeak: 28796 kB +VmSize: 28796 kB +VmLck: 0 kB +VmPin: 0 kB +VmHWM: 9212 kB +VmRSS: 9212 kB +RssAnon: 4708 kB +RssFile: 4504 kB +RssShmem: 0 kB +VmData: 16444 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 60 kB +VmSwap: 0 kB +# checkpoint 5 +VmPeak: 28796 kB +VmSize: 4216 kB +VmLck: 0 kB +VmPin: 0 kB +VmHWM: 9212 kB +VmRSS: 504 kB +RssAnon: 96 kB +RssFile: 408 kB +RssShmem: 0 kB +VmData: 56 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 28 kB +VmSwap: 0 kB +``` + +* 表 5-5 /proc/meminfo 在各检查点上的数值 +```bash +# checkpoint 1 +MemTotal: 1863220 kB +MemFree: 163052 kB +MemAvailable: 730148 kB +Buffers: 2116 kB +Cached: 785260 kB +SwapCached: 0 kB +Active: 824652 kB +Inactive: 613544 kB +Active(anon): 651680 kB +Inactive(anon): 108456 kB +Active(file): 172972 kB +Inactive(file): 505088 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 2097148 kB +SwapFree: 2097148 kB +Dirty: 20 kB +Writeback: 0 kB +AnonPages: 650840 kB +Mapped: 238944 kB +Shmem: 109316 kB +Slab: 100516 kB +SReclaimable: 40256 kB +SUnreclaim: 60260 kB +KernelStack: 9824 kB +PageTables: 36296 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028756 kB +Committed_AS: 4352980 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 215276 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 159744 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 132992 kB +DirectMap2M: 1964032 kB +DirectMap1G: 0 kB +# checkpoint 2 +MemTotal: 1863220 kB +MemFree: 140452 kB +MemAvailable: 707748 kB +Buffers: 2116 kB +Cached: 788908 kB +SwapCached: 0 kB +Active: 843484 kB +Inactive: 617104 kB +Active(anon): 670424 kB +Inactive(anon): 112096 kB +Active(file): 173060 kB +Inactive(file): 505008 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 2097148 kB +SwapFree: 2097148 kB +Dirty: 8 kB +Writeback: 0 kB +AnonPages: 669584 kB +Mapped: 241992 kB +Shmem: 112956 kB +Slab: 100984 kB +SReclaimable: 40640 kB +SUnreclaim: 60344 kB +KernelStack: 9776 kB +PageTables: 36024 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028756 kB +Committed_AS: 4346340 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 215276 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 225280 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 132992 kB +DirectMap2M: 1964032 kB +DirectMap1G: 0 kB +# checkpoint 3 +MemTotal: 1863220 kB +MemFree: 115132 kB +MemAvailable: 690628 kB +Buffers: 2116 kB +Cached: 799788 kB +SwapCached: 0 kB +Active: 855404 kB +Inactive: 627976 kB +Active(anon): 682336 kB +Inactive(anon): 114792 kB +Active(file): 173068 kB +Inactive(file): 513184 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 2097148 kB +SwapFree: 2097148 kB +Dirty: 24 kB +Writeback: 0 kB +AnonPages: 681496 kB +Mapped: 248424 kB +Shmem: 115652 kB +Slab: 101092 kB +SReclaimable: 40672 kB +SUnreclaim: 60420 kB +KernelStack: 9824 kB +PageTables: 36324 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028756 kB +Committed_AS: 4376652 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 215276 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 264192 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 132992 kB +DirectMap2M: 1964032 kB +DirectMap1G: 0 kB +# checkpoint 4 +[hypo@localhost ~]$ cat /proc/meminfo +MemTotal: 1863220 kB +MemFree: 110004 kB +MemAvailable: 685816 kB +Buffers: 2116 kB +Cached: 802524 kB +SwapCached: 0 kB +Active: 857812 kB +Inactive: 630520 kB +Active(anon): 684552 kB +Inactive(anon): 117476 kB +Active(file): 173260 kB +Inactive(file): 513044 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 2097148 kB +SwapFree: 2097148 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 683712 kB +Mapped: 250696 kB +Shmem: 118336 kB +Slab: 101576 kB +SReclaimable: 41196 kB +SUnreclaim: 60380 kB +KernelStack: 9792 kB +PageTables: 36064 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028756 kB +Committed_AS: 4351288 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 215276 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 278528 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 132992 kB +DirectMap2M: 1964032 kB +DirectMap1G: 0 kB +# checkpoint 5 +MemTotal: 1863220 kB +MemFree: 110996 kB +MemAvailable: 686816 kB +Buffers: 2116 kB +Cached: 805216 kB +SwapCached: 0 kB +Active: 854320 kB +Inactive: 633204 kB +Active(anon): 681052 kB +Inactive(anon): 120164 kB +Active(file): 173268 kB +Inactive(file): 513040 kB +Unevictable: 0 kB +Mlocked: 0 kB +SwapTotal: 2097148 kB +SwapFree: 2097148 kB +Dirty: 4 kB +Writeback: 0 kB +AnonPages: 680212 kB +Mapped: 248896 kB +Shmem: 121024 kB +Slab: 101584 kB +SReclaimable: 41204 kB +SUnreclaim: 60380 kB +KernelStack: 9760 kB +PageTables: 36040 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028756 kB +Committed_AS: 4338120 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 215276 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 274432 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 132992 kB +DirectMap2M: 1964032 kB +DirectMap1G: 0 kB +``` +* 页表的动态分配与回收 + +### 5.3.4 内存回收 +回收就是将已分配的在用页帧重新回到buddy 系统管理之下,以解决内存紧缺问题——回到buddy 系统作为空闲页帧可以被再次分配使用。可回收的页帧包括未修改过的文件映射页、修改过但是完成同步的文件映射页、未修改过的匿名页和已经换出到交换设备的匿名页。回收过程就是解除这些页的使用(包括解除页表映射等工作),归还给buddy 系统管理,可以再次被分配使用。用户进程可以锁定内存,使得它们不会被回收。 +![image](./record/pic/biao5-6.png) +系统调用 mlock 族函数允许程序锁住它的部分地址空间,这将阻止Linux 将这些内存页回收,哪怕该程序已不再访问这段空间。锁住的匿名页不会被换出和回收;锁住的文件映射页可以回写/同步,但是不会被回收。 +* 回写(同步)与交换 +回写(同步)操作是针对文件映射页的,而换出操作则是和匿名页相关的。回收、同步(回写)和换出三个操作都是以页帧为单位. +(1)回写:文件的写操作往往只修改页缓存中的内容即可返回,因此会出现页缓存和盘上数据的不一致的可能。通过同步(回写)操作才能保证盘上数据和内存(物理页帧)中缓存的数据相同。 +(2)换出:换出是匿名页回收的一个必要步骤,仅针对无文件映射的可回收页帧 +(3)回收:回收操作则是涉及物理页帧分配使用的问题,将可回收页解除使用者的页表映射并将页 +帧另作他用。 +* 进程间的页帧竞争 +用户进程并没有办法直接控制内存回收,只能通过进程间的物理页帧分配的竞争,侧面观察到内存回收、交换和回写的过程。 + +* 屏显 5-36 reclaim-swap-writeback-demo.c 创建并锁定内存后的内存布局/proc/PID/maps +```bash +[hypo@localhost ~]$ cat /proc/10227/maps +7f1d07cf2000-7f1d07cf7000 rw-p 00000000 00:00 0 +7f1d07cf7000-7f1d08cf3000 rw-p 00000000 00:00 0 +7f1d08cf3000-7f1d08cf5000 rw-s 00000000 fd:00 244 /home/hypo/tempfile +7f1d08cf5000-7f1d094f3000 rw-s 00002000 fd:00 244 /home/hypo/tempfile +``` +* reclaim-swap-writeback-demo.c 执行结果 +```bash +[hypo@localhost code]$ ./reclaim-swap-writeback-demo +allocated/mmapped +filemapped @ 0x7f1d08cf3000 +anon @ 0x7f1d07cf2010 +write finish +please run pages-blackhole-demo +compete for the page frames +``` +* 检查点说明 +checkpoint 1:在进程初始布局之上,创建两个新的内存区间,一个是8MB 的文件映射,一个是16MB 的非文件映射(匿名)区间。各自用mlock()函数锁定8KB 和16KB 的空间(不可换出) +checkpoint 2:对文件映射区间的前4MB 和匿名区间的前8MB 进行读和写操作各一遍。 +checkpoint 3:pagesblackhole-demo 进程将大量消耗物理页帧,因此会引起reclaim-swap-writeback-demo进程的页帧被回收。 +checkpoint 4:最后将通过对文件映射区间的前4MB 和匿名区间的前8MB 进行反复的读写操作。可以检查该进程重新获得物理页帧的现象。 + +* 表 5-7 /proc/PID/smaps 在各检查点上的数值 +```bash +# checkpoint 1 +7f1d07cf2000-7f1d07cf7000 rw-p 00000000 00:00 0 +Size: 20 kB +Rss: 20 kB +Pss: 20 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 20 kB +Referenced: 20 kB +Anonymous: 20 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 20 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me lo ac sd +7f1d07cf7000-7f1d08cf3000 rw-p 00000000 00:00 0 +Size: 16368 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7f1d08cf3000-7f1d08cf5000 rw-s 00000000 fd:00 244 /home/hypo/tempfile +Size: 8 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 8 kB +Private_Dirty: 0 kB +Referenced: 8 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 8 kB +ProtectionKey: 0 +VmFlags: rd wr sh mr mp me ms lo sd +7f1d08cf5000-7f1d094f3000 rw-s 00002000 fd:00 244 /home/hypo/tempfile +Size: 8184 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +# checkpoint 2 +7f1d07cf2000-7f1d07cf7000 rw-p 00000000 00:00 0 +Size: 20 kB +Rss: 20 kB +Pss: 20 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 20 kB +Referenced: 20 kB +Anonymous: 20 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 20 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me lo ac sd +7f1d07cf7000-7f1d08cf3000 rw-p 00000000 00:00 0 +Size: 16368 kB +Rss: 9252 kB +Pss: 9252 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 9252 kB +Referenced: 9252 kB +Anonymous: 9252 kB +AnonHugePages: 8192 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7f1d08cf3000-7f1d08cf5000 rw-s 00000000 fd:00 244 /home/hypo/tempfile +Size: 8 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 8 kB +Referenced: 8 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 8 kB +ProtectionKey: 0 +VmFlags: rd wr sh mr mp me ms lo sd +7f1d08cf5000-7f1d094f3000 rw-s 00002000 fd:00 244 /home/hypo/tempfile +Size: 8184 kB +Rss: 4088 kB +Pss: 4088 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 4088 kB +Referenced: 4088 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +# checkpoint 3 +7f1d07cf2000-7f1d07cf7000 rw-p 00000000 00:00 0 +Size: 20 kB +Rss: 20 kB +Pss: 20 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 20 kB +Referenced: 20 kB +Anonymous: 20 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 20 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me lo ac sd +7f1d07cf7000-7f1d08cf3000 rw-p 00000000 00:00 0 +Size: 16368 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 9252 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7f1d08cf3000-7f1d08cf5000 rw-s 00000000 fd:00 244 /home/hypo/tempfile +Size: 8 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 8 kB +Private_Dirty: 0 kB +Referenced: 8 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 8 kB +ProtectionKey: 0 +VmFlags: rd wr sh mr mp me ms lo sd +7f1d08cf5000-7f1d094f3000 rw-s 00002000 fd:00 244 /home/hypo/tempfile +Size: 8184 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +# checkpoint 4 +7f1d07cf2000-7f1d07cf7000 rw-p 00000000 00:00 0 +Size: 20 kB +Rss: 20 kB +Pss: 20 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 20 kB +Referenced: 20 kB +Anonymous: 20 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 20 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me lo ac sd +7f1d07cf7000-7f1d08cf3000 rw-p 00000000 00:00 0 +Size: 16368 kB +Rss: 2028 kB +Pss: 2028 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 2028 kB +Referenced: 2028 kB +Anonymous: 2028 kB +AnonHugePages: 0 kB +Swap: 7224 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +ProtectionKey: 0 +VmFlags: rd wr mr mp me ac sd +7f1d08cf3000-7f1d08cf5000 rw-s 00000000 fd:00 244 /home/hypo/tempfile +Size: 8 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 8 kB +Referenced: 8 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 8 kB +ProtectionKey: 0 +VmFlags: rd wr sh mr mp me ms lo sd +7f1d08cf5000-7f1d094f3000 rw-s 00002000 fd:00 244 /home/hypo/tempfile +Size: 8184 kB +Rss: 1016 kB +Pss: 1016 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 1016 kB +Referenced: 1016 kB +Anonymous: 0 kB +AnonHugePages: 0 kB +Swap: 0 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Locked: 0 kB +``` + +* 表 5-8 /proc/PID/status 在各检查点上的数值 +```bash +# checkpoint 1 +VmPeak: 28796 kB +VmSize: 28796 kB +VmLck: 28 kB +VmPin: 0 kB +VmHWM: 352 kB +VmRSS: 352 kB +RssAnon: 76 kB +RssFile: 276 kB +RssShmem: 0 kB +VmData: 16444 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 36 kB +VmSwap: 0 kB +Threads: 1 +# checkpoint 2 +VmPeak: 28796 kB +VmSize: 28796 kB +VmLck: 28 kB +VmPin: 0 kB +VmHWM: 13744 kB +VmRSS: 13744 kB +RssAnon: 9212 kB +RssFile: 4532 kB +RssShmem: 0 kB +VmData: 16444 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 60 kB +VmSwap: 0 kB +Threads: 1 +# checkpoint 3 +VmPeak: 28796 kB +VmSize: 28796 kB +VmLck: 28 kB +VmPin: 0 kB +VmHWM: 13744 kB +VmRSS: 28 kB +RssAnon: 0 kB +RssFile: 28 kB +RssShmem: 0 kB +VmData: 16444 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 60 kB +VmSwap: 9348 kB +Threads: 1 +# checkpoint 4 +VmPeak: 28796 kB +VmSize: 28796 kB +VmLck: 28 kB +VmPin: 0 kB +VmHWM: 13744 kB +VmRSS: 3088 kB +RssAnon: 2056 kB +RssFile: 1032 kB +RssShmem: 0 kB +VmData: 16444 kB +VmStk: 132 kB +VmExe: 4 kB +VmLib: 1936 kB +VmPTE: 60 kB +VmSwap: 7312 kB +Threads: 1 +``` + +* 表 5-9 /proc/meminfo 在各检查点上的数值 +```bash +# checkpoint 1 +MemTotal: 1863248 kB +MemFree: 67188 kB +MemAvailable: 556916 kB +Buffers: 172 kB +Cached: 806276 kB +SwapCached: 0 kB +Active: 881212 kB +Inactive: 577388 kB +Active(anon): 586216 kB +Inactive(anon): 284320 kB +Active(file): 294996 kB +Inactive(file): 293068 kB +Unevictable: 28 kB +Mlocked: 28 kB +SwapTotal: 2097148 kB +SwapFree: 2096628 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 652388 kB +Mapped: 337764 kB +Shmem: 218376 kB +Slab: 134840 kB +SReclaimable: 65512 kB +SUnreclaim: 69328 kB +KernelStack: 10128 kB +PageTables: 37096 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028772 kB +Committed_AS: 4560968 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 216300 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 190464 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 141184 kB +DirectMap2M: 1955840 kB +DirectMap1G: 0 kB +# checkpoint 2 +MemTotal: 1863248 kB +MemFree: 63872 kB +MemAvailable: 516796 kB +Buffers: 172 kB +Cached: 793440 kB +SwapCached: 4 kB +Active: 872652 kB +Inactive: 589336 kB +Active(anon): 596768 kB +Inactive(anon): 313804 kB +Active(file): 275884 kB +Inactive(file): 275532 kB +Unevictable: 28 kB +Mlocked: 28 kB +SwapTotal: 2097148 kB +SwapFree: 2096628 kB +Dirty: 8 kB +Writeback: 0 kB +AnonPages: 668440 kB +Mapped: 363284 kB +Shmem: 242188 kB +Slab: 134620 kB +SReclaimable: 65196 kB +SUnreclaim: 69424 kB +KernelStack: 10192 kB +PageTables: 37432 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028772 kB +Committed_AS: 4611936 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 216300 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 229376 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 141184 kB +DirectMap2M: 1955840 kB +DirectMap1G: 0 kB +# checkpoint 3 +MemTotal: 1863248 kB +MemFree: 56520 kB +MemAvailable: 14148 kB +Buffers: 0 kB +Cached: 48440 kB +SwapCached: 15360 kB +Active: 1161024 kB +Inactive: 405136 kB +Active(anon): 1150128 kB +Inactive(anon): 385492 kB +Active(file): 10896 kB +Inactive(file): 19644 kB +Unevictable: 28 kB +Mlocked: 28 kB +SwapTotal: 2097148 kB +SwapFree: 644996 kB +Dirty: 0 kB +Writeback: 124 kB +AnonPages: 1502756 kB +Mapped: 23996 kB +Shmem: 17496 kB +Slab: 97976 kB +SReclaimable: 34104 kB +SUnreclaim: 63872 kB +KernelStack: 10176 kB +PageTables: 41284 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028772 kB +Committed_AS: 6646500 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 216300 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 8192 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 141184 kB +DirectMap2M: 1955840 kB +DirectMap1G: 0 kB +# checkpoint 4 +MemTotal: 1863248 kB +MemFree: 71752 kB +MemAvailable: 24264 kB +Buffers: 0 kB +Cached: 42428 kB +SwapCached: 60244 kB +Active: 1157844 kB +Inactive: 394680 kB +Active(anon): 1145672 kB +Inactive(anon): 385636 kB +Active(file): 12172 kB +Inactive(file): 9044 kB +Unevictable: 28 kB +Mlocked: 28 kB +SwapTotal: 2097148 kB +SwapFree: 589384 kB +Dirty: 932 kB +Writeback: 100 kB +AnonPages: 1449988 kB +Mapped: 28548 kB +Shmem: 21280 kB +Slab: 97332 kB +SReclaimable: 33368 kB +SUnreclaim: 63964 kB +KernelStack: 10240 kB +PageTables: 41580 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 3028772 kB +Committed_AS: 6683348 kB +VmallocTotal: 34359738367 kB +VmallocUsed: 216300 kB +VmallocChunk: 34359277564 kB +HardwareCorrupted: 0 kB +AnonHugePages: 8192 kB +CmaTotal: 0 kB +CmaFree: 0 kB +HugePages_Total: 0 +HugePages_Free: 0 +HugePages_Rsvd: 0 +HugePages_Surp: 0 +Hugepagesize: 2048 kB +DirectMap4k: 141184 kB +DirectMap2M: 1955840 kB +DirectMap1G: 0 kB +``` + +## 课后作业 +### 1.请编写程序分配几K 的空间,然后通过free()回收的空间,验证该空间仍可以合法访问。不断增大所分配的空间并进行回收,探测出在什么尺度上的内存空间回收会造成不可访问。 +思路:循环分配内存然后回收并访问,若成功则增加内存的分配量然后重复上述流程,直到出现错误 + +代码如下: +```c +#include +#include + +#define kB 1024 +void *p; +int main() +{ + int i = 8; + while(1) + { + p = malloc(i*kB); + free(p); + printf("%d,succeed,%s\n",i,p); + i++; + } + return 0; +} +``` +运行结果如下: +```bash +[hypo@localhost homework]$ ./problem1 +8,succeed, +9,succeed, +10,succeed, +11,succeed, +12,succeed, +13,succeed, +..... +125,succeed, +126,succeed, +127,succeed, +128,succeed, +129,succeed, +130,succeed, +131,succeed, +Segmentation fault (core dumped) +``` +![image](./homework/problem1.png) +通过运行结果可以发现当分配的内存达到132kb时,回收空间后该空间将无法访问。 + +### 2.设计一个程序,用于验证Linux 进程用户空间的管理是否属采用了最佳匹配算法。 + +思路:连续分配1,2,4,8,16,32,64kb内存,但每个内存块中均用1kb非空闲内存进行分隔,最佳匹配算法只会分配满足条件的最接近的内存区域,验证是否是即可。 +代码: + +```c +#include +#include +#define kb 1024 + +void *bufs[134]; //1+1+1+2+1+4+1+8+1+16+1+32+1+64 = 134 +// int list[]={0,2,5,10,19,36,69}; + +int main(){ + int i; + for (i = 0; i < 134; ++i){ + bufs[i] = malloc(1*kb); + } + + for (i = 0; i < 134; ++i){ + if (i==0) + printf("<1kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 2) + printf("1~2kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 5) + printf("2~4kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 10) + printf("4-8kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 19) + printf("8-16kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 36) + printf("16-32kb pre-addr:%p\n",bufs[i+1] ); + else if (i == 69) + printf("32-64kb pre-addr:%p\n",bufs[i+1] ); + else + free(bufs[i]); + } + + while(1){ + int size; + printf("input size(<64kb):\n"); + scanf("%d",&size); + void *ptr; + ptr = malloc(size*kb); + printf("true:addr:%p\n",ptr ); + } + return 0; +} +``` +运行结果: +```bash +[hypo@localhost homework]$ ./problem2 +<1kb pre-addr:0x7d6420 +1~2kb pre-addr:0x7d6c40 +2~4kb pre-addr:0x7d7870 +4-8kb pre-addr:0x7d8cc0 +8-16kb pre-addr:0x7db150 +16-32kb pre-addr:0x7df660 +32-64kb pre-addr:0x7e7c70 +input size(<64kb): +7 +true:addr:0x7d8cc0 +input size(<64kb): +65 +true:addr:0x7e7c70 +input size(<64kb): +``` +![image](./homework/problem2.png) + + +### 3.设计一个程序A,分配大量内存并填充某种模式的字符串,然后进入阻塞状态。然后通过另一程序B 分配大量内存并反复访问。设法查看A 进程的换出情况,以及相应换出页的页表项内容。 +代码:A +```c +#include +#include +#include +#include +#include +#define MB (1024*1024) +int main() +{ + int pid,i; + char *buf; + pid = getpid(); + printf("PID:%d\n",pid ); + buf=(char*)malloc(1024*MB); + printf("addr_start:%p\n",buf); + for(i=0;i<1024*MB;i++) + { + buf[i]=0xaa; + } + printf("addr_end:%p\n",&buf[i]); + long size = &buf[i]-&buf[0]; + printf("malloc size:%dMB\n", size/MB); + printf("please run pages-blackhole-demo\n"); + getchar(); + free(buf); + return 0; +} +``` +代码:B +```c +#include +#include +#include +#include +#define MB 1024*1024 +int main() +{ + int i,j; + char temp; + int fd= -1; + char * filemap_buf; + char * anon_buf; + anon_buf=(char *)malloc(1000*MB); + while(1) + { + for(i=0;i<1000*MB;i+=4096) + anon_buf[i]=0xaa; + sleep(1); + } + return 0; +} +``` +结果: +```bash +#运行前free结果 +[hypo@localhost ~]$ free + total used free shared buff/cache available +Mem: 1863248 520728 994812 89348 347708 1043556 +Swap: 2097148 855548 1241600 +#运行A结果 +[hypo@localhost homework]$ ./problem3_a +PID:15352 +addr_start:0x7f540c076010 +addr_end:0x7f544c076010 +malloc size:1024MB +please run pages-blackhole-demo +#运行free结果,发现RAM占用上升1G +[hypo@localhost ~]$ free + total used free shared buff/cache available +Mem: 1863248 1567736 66200 85324 229312 32076 +Swap: 2097148 863004 1234144 +#运行B后free结果,发现swap分区上升1G +[hypo@localhost ~]$ free + total used free shared buff/cache available +Mem: 1863248 1608888 63744 38280 190616 33664 +Swap: 2097148 1842800 254348 +#使用crash工具查看换出结果 +#计算结果: +#addr_start:0x7f540c076010 +#PGD 中的索引/偏移: (0x7f540c076010>>(9+ 9 + 9 + 12)) & 0x1ff = 0xFE ->760 +#PUD 中的索引/偏移: (0x7f540c076010>>(9 + 9 + 12)) & 0x1ff = 0x150 ->a80 +#PMD 中的索引/偏移: (0x7f540c076010>>(9 + 12)) & 0x1ff = 0x60 -> 300 +#PDTE 中的索引/偏移: (0x7f540c076010>>(12)) & 0x1ff = 0x76 -> 3b0 +#页内偏移: (0x7f540c076010>>(0)) & 0xfff = 0x010 -> 80 +crash> set 15352 + PID: 15352 +COMMAND: "problem3_a" + TASK: ffff8be4d3e8a080 [THREAD_INFO: ffff8be4fa6c4000] + CPU: 1 + STATE: TASK_INTERRUPTIBLE +crash> px ((struct task_struct *)0xffff8be4d3e8a080)->mm->pgd +$1 = (pgd_t *) 0xffff8be4d14ae000 +crash> px (0xffff8be4d14ae000-0xffff880000000000) +$2 = 0x3e4d14ae000 +crash> rd 0xffff8be4d14ae7F0 +ffff8be4d14ae7f0: 8000000076d2c067 g..v.... +crash> pte 8000000076d2c067 + PTE PHYSICAL FLAGS +8000000076d2c067 76d2c000 (PRESENT|RW|USER|ACCESSED|DIRTY|NX) +crash> rd -p 76d2ca80 + 76d2ca80: 0000000071615067 gPaq.... +crash> pte 0000000071615067 + PTE PHYSICAL FLAGS +71615067 71615000 (PRESENT|RW|USER|ACCESSED|DIRTY) +crash> rd -p 71615300 + 71615300: 0000000070ca2067 g .p.... +crash> pte 0000000070ca2067 + PTE PHYSICAL FLAGS +70ca2067 70ca2000 (PRESENT|RW|USER|ACCESSED|DIRTY) +crash> rd -p 70ca23b0 + 70ca23b0: 07fffffff6c4de80 ........ +crash> pte 07fffffff6c4de80 + PTE SWAP OFFSET +7fffffff6c4de80 /dev/dm-1 2251799813080286 +#使用crash查看相应换出页的页表项内容,发现换出页储存在swap交换分区 +crash> +``` +截图: +1.A运行结果 +![image](./homework/problem3_A.png) +2.free命令结果 +![image](./homework/problem3_free.png) +3.使用crash查看相应换出页的页表项内容,发现换出页储存在swap交换分区 +![image](./homework/problem3_crash.png) + +结论:当RAM不足时,休眠状态的程序将被换出至swap交换分区 + +## 实验体会 +通过本次实验,对linux系统的内存管理系统有了较好的理解。