操作系统实验三 内存分配及回收研究

news2024/9/20 17:50:27

前言

本次实验跟前两次相比简单许多,主要是体会底层的一些运行机制。其实,要说简单,也不是真的很简单,毕竟还是存在一些更底层的东西需要我们去探讨。接下来就让我们通过实验来感受一下。

1.实验目的

掌握Linux操作系统的内存分配与使用的编程接口;

掌握Linux操作系统中进程虚拟内存的映射;

通过本次实验体会Linux操作系统中内存的分配模式;

2.实验内容

学习Linux系统的内存动态申请、释放的函数;

学习Linux操作系统提供的进程地址映射的工具;

观察进程用户空间的虚存管理变化,包括堆区、文件映射区和栈区;

3.实验的内容与过程

任务1

写出/proc/$pid/maps数据各字段含义;(pid是对应的进程号,终端会输出的,因为原代码中getpid函数会获取对应的进程号)

 

一个终端用来运行代码,一个终端用来查看信息:(编译用gcc命令即可)

数据各字段含义:

第一列:虚拟地址空间起始地址

第二列:虚拟地址空间结束地址

第三列:虚拟地址空间的属性。每种属性用一个字段表示,r表示可读,w表示可写,x表示可执行,p和s共用一个字段,互斥关系,p表示私有段,s表示共享段,如果没有相应权限,则用‘-’代替;

第四列:虚拟内存区域在被映射文件中的偏移量

第五列:文件的主设备号和次设备号

第六列:设备的节点号,0表示没有节点与内存相对应

第七列:被映射文件的文件名

任务2 

运行代码,观察进程空间变化(/proc/$pid/maps)过程,截图简要说明进程空间变化的内容,截图画出变量所在内存段;

第一次cat /proc/$pid/maps:

注:BSS段(Block-started by Symbol段)是指未被初始化的全局变量或者静态变量所占用的内存区段。Stack_var0和Stack_var1都为临时变量。在数据段中,初始化了的全局变量、静态变量在data段,未初始化的在bss段

分析:

通过观察发现,在终端中已经输出了一些信息。再仔细看这些输出信息,通过与上张图的地址对比,我们发现每个地址都在其对应位置的起始地址和结束地址之间。如:Stack_var0和Stack_var1都为临时变量,因此两者应该存储在栈内,通关观察,确实如此!(0x7fffe785abcc和0x7fffe785abc8在0x7fffe783b000~0xfffe785c000中,以后的情况也是这么分析)接下来我们结合代码看看此时程序运行到哪里了。

主函数:

分析:

可以看到在主函数中先输出了进程号,然后不断调用了很多自定义函数,接下来我们就一个一个查看自定义函数。

TextLocation函数:

分析:可以看到输出信息和终端对上了,但还是会继续运行。

StackLocation函数:

分析:也是打印出相应信息,然后继续代码运行。

DataSegmentLocation函数:

分析:打印相应的信息,遇到了getchar函数,此时代码停止运行,等待我们输入一个字符后才继续执行。接下来我们输入回车,将代码继续执行下去。

第二次cat /proc/$pid/maps:

分析:

输入了回车后,我们发现输出的信息中堆多了一行。通过观察我们可以发现,输出的堆区地址在多出的这一行新建堆区的起始地址与结束地址之内。接下来我就结合代码来看看是怎么回事。(主函数中已经执行完了DataSegmentLocation函数,接下来执行HeapLocation函数)

HeapLocation函数:

分析:

首先代码中先打印出相关信息,然后又创建了两个大小都为60MB的堆,接着输出这两个堆的位置。通过输出信息,第一个堆的位置为0x7f8e25e9b010,第二个堆的位置为0x7f8e2229a010,0x7f8e25e9b010-0x7f8e2229a010=0x3C0 1000=62,918,656B=60MB。因此,我们可以判断这两个堆是连续的。接着回车

第三次cat /proc/$pid/maps:

分析:

通过输出提示还有cat的输出结果我们可以知道刚刚动态创建的堆已经释放掉了。下面结合代码看看。(代码部分在HeapLocation中)

分析:

通过查看代码,新建堆确实释放了。接着回车继续执行。

第四次cat /proc/$pid/maps:

分析:

通过观察发现,发现在终端输出了文件映射的地址。通过观察图二的文件映射名并比较其的起始地址和结束地址,我们发现文件映射的地址确实是在起始地址与结束地址之间。接下来结合代码分析。

分析:

这个代码主要是打开文件“map-file.txt”,如果没有就创建一个。然后往这个文件内写内容。运行后可以发现目录下多了个文件,里面有输入的内容。

接下来输入回车继续运行。

第五次cat /proc/$pid/maps:

分析:

可以看到,刚刚的文件映射已经没有了,结合代码看看。

分析:

主要是关闭文件,所以文件映射才会消失。

至此,任务2已经全部完成了。

任务3:

编写程序,连续申请分配六个128MB空间(记为1~6号),然后释放第2、3、5号的128MB空间。然后再分配1024MB,记录该进程的虚存空间变化(/proc/$pid/maps),每次操作前后检查/proc/$pid/status文件中关于内存的情况,简要说明虚拟内存变化情况。推测此时再分配64M内存将出现在什么位置,实测后是否和你的预测一致?解释说明用户进程空间分配属于课本中的离散还是连续分配算法?首次适应还是最佳适应算法?

第三次cat /proc/$pid/maps(再分配1024MB)

分析:

通过与第二次cat的结果对比,只有新输出的第一行的起始地址改变了,说明第一行的起始地址到结束地址中存放着heap[5]和big heap。通过计算0x7f457c613000-0x7f453c612000=0x40001000=1024MB,改变的起始地址和原来的起始地址之间的差的大小刚好为1024MB,更能说明bigheap和heap[5]是连续的。

第四次cat /proc/$pid/maps(再分配64MB)

分析:

通过对比,我们发现newheap的空间是跟在heap[0]后面的,因为heap[1]已经释放了,128MB的大小是足够存放64MB的大小的。因此,我们能得出结论:用户进程空间分配是连续分配、首次适应算法。(找到第一个符合要求的空间便进行分配)。

代码

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

int main(int argc, char **argv)
{
    void *heaps[6], *bigHeap; //存放六个空间较小且连续的堆和一个空间较大的堆
    int i = 0;

    
	printf("Process ID:%d\n",getpid());//打印出进程号   

    printf("Malloc 6 heaps(size: 128MB):\n"); //输出提示信息
    for (int i = 0; i < 6; i++)
    {
        heaps[i] = malloc(128 * 1024 * 1024);                 //为堆分配空间(128MB)
        printf("\tAddress of heap[%d] is %p\n", i, heaps[i]); //输出堆的地址
    }
    printf("Please check /proc/PID/maps and /proc/PID/status file to check the change,press Enter to continue!\n"); //输出信息
    getchar();                                                                                                      //等待下一次操作(回车)

    //释放2、3、5号堆
    free(heaps[1]);
    free(heaps[2]);
    free(heaps[4]);
    printf("Please check /proc/PID/maps and /proc/PID/status file to check the change,press Enter to continue!\n"); //输出信息
    getchar();

    printf("Malloc big heap(size: 1024MB):\n"); //创建空间大的堆
    bigHeap = malloc(1024 * 1024 * 1024);       // 1024MB的堆
    printf("\tbig heap is %p\n", bigHeap);
    printf("Please check /proc/PID/maps and /proc/PID/status file to check the change,press Enter to continue!\n"); //输出信息
    getchar();     //等待下一次操作(回车)
    
    printf("Malloc new heap(size: 64MB):\n"); //再创建64MB的内存
    void *newHeap=malloc(64*1024*1024);
    printf("\tnew heap is %p\n", newHeap);
    printf("Please check /proc/PID/maps and /proc/PID/status file to check the change,press Enter to continue!\n"); //输出信息
    getchar();     //等待下一次操作(回车)

    //释放剩下的堆
    free(heaps[0]);
    free(heaps[3]);
    free(heaps[5]);
    free(bigHeap);
    printf("Please check /proc/PID/maps and /proc/PID/status file to check the change,press Enter to continue!\n"); //输出信息
    getchar();//等待下一次操作(回车)

    return 0;

}

在实验中,我发现一个有趣的现象。我们新生成的堆的地址比旧堆地址要小,这跟栈是不一样的(栈是从低地址开始,往高地址开辟)。经过询问老师知道这跟结构有关系,如下图:

 

感兴趣的同学可以自行了解,我就不过多赘述。

至此,我们的实验大功告成!如果大家有什么想法,可以在评论区提出,一起交流。

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

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

相关文章

地表水灌区取水计量设施包含哪些设备?

方案背景 根据《关于强化取水口取水监测计量的意见》、《十四五”节水型社会建设规划》以及《2022年水资源管理工作要点》等政策要求&#xff0c;为强化水资源管理&#xff0c;做好水资源税改革&#xff0c;构建节水型社会&#xff0c;要全面加强取水计量监测设施建设&#xff…

【计算机系统基础3】数据的存储与运算

3.程序调试与实践&#xff1a;数据存储与运算 3.1真值与机器数 真值&#xff1a; 数据在现实世界中的表示 机器数&#xff1a; 数据在计算机内部的二进制编码表示 温度&#xff1a;零下3.5度 习惯写法&#xff1a;-3.5 (数据的真值/数据的实际值) 3.1.1整数的编码 带符号整数&…

15:13进去面试,5分钟就完事了,问的实在是太......

干了两年外包&#xff0c;本来想出来正儿八经找个互联网公司上班&#xff0c;没想到算法死在另一家厂子。 自从加入这家外包公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到11月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资…

2023年值得关注的低代码平台推荐

低代码平台在数字化转型的浪潮中受到越来越多企业的青睐&#xff0c;因为它们提供了一种更容易、更快的方式来开发网络和移动应用程序。低代码平台只需要最少的编码知识&#xff0c;使公司能够在很短的时间内开发出定制的应用程序&#xff0c;而这只是使用传统的搭建手段所需时…

参数传递之传名,传地址,得结果,传值

编译原理速成&#xff0c;参数传递之传名&#xff0c;传地址&#xff0c;得结果&#xff0c;传值(四)_哔哩哔哩_bilibili 学习自上面的文章。 题目1&#xff1a; &#xff08;1&#xff09;传名。 (2)传地址。&#xff08;注意观察&#xff0c;AB变成了临时变量T1&#xff0c;…

jvm之G1 GC

写在前面 jdk9以及之后的版本已经将默认的垃圾收集器parallel更换为G1.本文就一起来看下。 1&#xff1a;G1介绍 parallel GC的设计目标是高吞吐量&#xff0c;CMS GC的设计目标是低延迟&#xff0c;而G1的设计目标不是这二者中的任何一个&#xff0c;其设计目标是让GC的STW…

我的世界Fabric mod开发-快速漏斗

前往我的主页以阅读完整内容&#xff0c;并获取源码 DearXuan的主页 MOD介绍 使用漏斗链进行分类或传递物品时,常常会发现漏斗速度太慢,难以收集全部掉落物.或者漏斗太多,影响性能.而现有的漏斗加速mod则是引入新的快速漏斗,存在各种兼容问题.开服时发现paper服务器可以修改原…

华为OD机试真题 Java 实现【区间连接器】【2023Q1 200分】

一、题目描述 有一组区间 [a0, b0], [a1, b1], … (a, b 表示起点, 终点)&#xff0c;区间有可能重叠、相邻&#xff0c;重叠或相邻则可以合并为更大的区间&#xff1b; 给定一组连接器[x1, x2, x3, …]&#xff08;x 表示连接器的最大可连接长度&#xff0c;即 x>gap&…

支付宝沙箱支付(java电脑版)

目录 下载支付demo配置环境AlipayConfig 下载支付demo 网址&#xff1a;https://open.alipay.com/ 下载并打开项目发现无法运行&#xff1a; 手动转化项目&#xff1a; 等待下载整理一下maven pom 通过tomat部署运行测试。 导入阿里支付的pom依赖 <dependency> &l…

都2023了,你竟然还不知道网络安全该怎么学

前言 网络安全是指网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然或恶意原因而遭受破坏、更改、泄露&#xff0c;系统连续可靠正常地运行&#xff0c;网络服务不中断。网络安全因何而重要&#xff1f; 截至2023年4月,我国网民规模为_11.51亿_&#xff0c…

模板初阶(泛型编程)

模板初阶 &#x1f506;泛型编程&#x1f506;函数模板函数模板概念函数模板格式函数模板的原理函数模板的实例化模板参数的匹配原则 &#x1f506;类模板类模板的定义格式类模板的实例化类模板与模板类的区别 &#x1f506;结语 &#x1f506;泛型编程 泛型编程&#xff1a;编…

【总结】Numpy2

Numpy 1. 数组和数的运算 array1 np.arange(1,10) array1 # array([1, 2, 3, 4, 5, 6, 7, 8, 9]) array1 10 # array([11, 12, 13, 14, 15, 16, 17, 18, 19]) array1 - 10 # array([-9, -8, -7, -6, -5, -4, -3, -2, -1]) array1 * 10 # array([10, 20, 30, 40, 50, 60, 70…

Flutter:如何在Android中实现串口通信调试

本文介绍如何通过flutter_libserialport插件在Flutter中实现串口通信调试。 1、引入依赖 在flutter工程的pubspec.yaml文件中引入flutter_libserialport依赖&#xff1a; dependencies:flutter_libserialport: ^0.3.0 2、导入import依赖包 在dart代码中import导入flutter_li…

快手国际化 后端开发面经二面

目录 1.Redis用的什么数据类型2.Hash底层结构3.JVM垃圾判别阶段算法4.MySQL索引模型5.为什么用B树6.联合索引在B树如何构造的7.覆盖索引知道吗 1.Redis用的什么数据类型 1.String(字符类型) 2.Hash(散列类型) 3.List(列表类型) 4.Set(集合类型) 5.SortedSet(有序集合类型&…

设计模式 单例模式(创建型)

一、前言 学习设计模式我们关注的是什么&#xff0c;如何实现么&#xff1f;是也不是。我认为比了解如何实现设计模式更重要的是这些设计模式的应用场景&#xff0c;什么场景下我们该用这种设计模式&#xff1b;以及这些设计模式所包含的思想&#xff0c;最终帮助我们把代码写…

继承 + 多态 + final + 权限修饰符

目录 继承 多态 final 权限修饰符 继承 继承定义&#xff1a; 可以让类跟类之间产生子父的关系继承的好处 可以把多个子类中重复的代码抽取到父类中&#xff0c;子类可以直接使用&#xff0c;减少代码几余&#xff0c;提高代码的复用性子类继承内容 非私有private构造方法…

#机器学习--深度学习中的正则化

#机器学习--深度学习中的正则化 引言1、参数范数惩罚2、 L 2 L^{2} L2 正则化3、 L 1 L^{1} L1 正则化4、显式约束和重投影5、参数绑定和参数共享6、Bagging7、Dropout 引言 本系列博客旨在为机器学习(深度学习)提供数学理论基础。因此内容更为精简&#xff0c;适合二次学习的…

uniapp实现条码扫描 可开闪光灯,原生H5调用,不需要任何sdk。

主要思路 使用QuaggaJs这个库。调用摄像头使用的 navigator.mediaDevices.getUserMedia 这个H5的api。通过 video 和 canvas 把摄像头获取到的数据展现到页面上&#xff0c;同时调用监听Quagga解析。 获取设备摄像头权限,用于后续开启摄像头。创建video元素显示摄像头画面,和ca…

AcWing算法提高课-1.3.10混合背包问题

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 本题链接&#xff08;AcWing&#xff09; 点这里 题目描述 有 N N N 种物品和一个容量是 V V V 的背包。 物品一共有三类&#xff1a; 第一类物品只能用1次&#xff08;01背包&#xff0…

opencv相机标定

当你把摄像机放在一个特定的位置&#xff0c;在它的后面放一个目标图像&#xff0c;或者是把摄像机放到某个物体上&#xff0c;摄像机周围的物体是什么形状&#xff0c;你需要知道这些信息。 当你在计算机上处理图像时&#xff0c;会使用以下三个参数&#xff1a; 1.像素坐标&a…