湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制1《unix操作系统教程》课程实验报告实验名称Linux内存管理实验实验序号5姓名系院专业班级学号实验日期2012.11.28指导教师成绩一、实验目的1.通过在Linux环境下对内存管理的基本操作,感性认识Linux如何对内存进行管理。2.利用readelf和objdump观测linux下的内存地址映射过程以及进程的虚拟地址空间。二、实验内容与要求(1)按照实验内容完成实验操作步骤,学习内存管理中的一些常用命令(2)理解linux中逻辑地址、线性地址的概念。(3)提交实验报告。三、实验设备地点:实验实训中心A4-2设备:计算机一台linux操作系统湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制2四、实验步骤与测试实验一free命令显示显示内存的使用情况(使用的和空闲的),包括物理内存、交换区内存、内核缓冲区内存。不包括共享内存。free命令默认选项为-k语法:free[-bkmotV][-s间隔秒数]选项介绍:-b:以Byte为单位显示内存使用情况;-k:以KB为单位显示内存使用情况;-m:以MB为单位显示内存使用情况;-o:不显示缓冲区调节列;-s间隔秒数:每间隔指定时间执行一次free命令;-t:显示内存总和列;-V:显示版本信息;(1)free-k:以KB为单位显示内存使用情况;解释:total:内存总量:3355508(k)used:已经使用的内存量:490664(k)free:空闲的内存量:2864844(k)shared:当前已经废弃不用,总量是0(k)buffers:25164(k)BufferCache内存量:263480(k)cached:PageCache内存量:21436(k)(2)free–m-s5:以M为单位,5秒显示以下内存信息解释:以上为每隔5秒显示内存信息,由以上图可知:两次内存使用情况没有变化。(3)free-o:不显示缓冲区调节列;解释:由以上可知BufferCache这一列没有显示出来。(4)free-t:显示内存总和列;湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制3解释:如上所示,内存总和是3355508(k),内存已使用为491408(k),内存空闲为2864100(k)。(5)free-V:显示版本信息解释:版本号为3.2.72.swapon–s:显示交换区的使用状况解释:交换区名为:/dev/sda3,类型为partition,大小为425712,已使用为0,优先级为-1。3.vmstat是VirtualMeomoryStatistics(虚拟内存统计)的缩写,可对操作系统的虚拟内存、进程、CPU活动进行监视。它是对系统的整体情况进行统计,不足之处是无法对某个进程进行深入分析。解释:vmstat[-V][-n][delay[count]]其中,-V表示打印出版本信息;-n表示在周期性循环输出时,输出的头部信息仅显示一次;delay是两次输出之间的延迟时间;count是指按照这个时间间隔统计的次数。对于vmstat输出各字段的含义,可运行manvmstat查看。下面给出了各个参数的不同含义:procs:r--在运行队列中等待的进程数b--在等待io的进程数w--可以进入运行队列但被替换的进程memoyswap--现时可用的交换内存(k表示)free--空闲的内存(k表示)buff--被用来做为缓存的内存数,单位:KBcache--被用来做为文件读写缓存的内存数,单位:KBswapsi--从磁盘交换到内存的交换页数量,单位:KB/秒so--从内存交换到磁盘的交换页数量,单位:KB/秒IObi--磁盘块入湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制4bo--磁盘块出Systemin--每秒的中断数,包括时钟中断cs--每秒的环境(上下文)切换次数CPU按CPU的总使用百分比来显示us--用户进程使用的时间sy--系统进程使用的时间id--cpu空闲的时间pagesre--回收的页面mf--非严重错误的页面pi--进入页面数(k表示)po--出页面数(k表示)fr--空余的页面数(k表示)de--提前读入的页面中的未命中数sr--通过时钟算法扫描的页面disk显示每秒的磁盘操作。s表示scsi盘,0表示盘号fault显示每秒的中断数in--设备中断sy--系统中断cy--cpu交换实验二1.搭建linux实验平台,并在搭建好的平台中用vi编辑器编写一个简单C程序:1./*test.c*/2.3.#includestdio.h4.5.intglobal_data=4;6.7.intglobal_data_2;8.9.intmain(intargc,char**argv)10.11.{12.13.intlocal_data=3;14.湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制515.printf(HelloWorldn);16.17.printf(global_data=%dn,global_data);18.19.printf(global_data_2=%dn,global_data_2);20.21.printf(local_data=%dn,local_data);22.23.return(0);24.25.}2.编译:$gcc-otesttest.cA.查看ELF的头。刚生成的二进制就是我们要查看的目标。从ELF的头开始吧:$readelf-htest实验结果:可执行文件是可以在Intelx8632bit的体系的机器上运行的(从“machine”和“class”字段)。当执行时,程序将从虚地址0x080482c0(看“Entrypointaddress”)开始运行。这个地址不是指向我们常见的main()函数地址的,但是它指向是一个名为__start的函数。__start函数是被linker创建的,它的目标是初始你的程序。湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制6这个程序还有28个节区(section)和7个段(segment)什么是节区(section)?Section是在目标文件中的一个区,它包括一些信息(这些信息对连接过程有用):程序的代码、程序的数据(变量、数组、字符串),可重定向的信息和其它。所以,在每一个区,几种信息组合在一起,这里有一个明显地含义:代码区只有代码,数据区只是初始化的或是没有初始化的数据,等等。节区头部分列表(SectionHeaderTable,SHT)精确地告诉我们:ELF目标文件中有什么section。至少从“Numberofsectionheaders”字段中知道“test”目标文件有28个section.如果section是一个二进制表示的,linux内核不能用一种方式读懂它,linux内核准备几个VMA(VirtualMemoryArea),它们包括虚拟地址连续的页面帧。在VMA的内部,一个或多个section被映射其中。在这个例子中每一个VMA都代表一个ELF的段(segment)。那内核是如何知道哪个section去往哪个segment呢?这是ProgramHeaderTable(PHT)的工作。B.查看SectionHeaderTable(SHT)让我们看一个Section在程序中的存在形式:$readelf-Stest实验结果:湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制7编译器把可执行代码保存到.text节区中。那.text节区被标记为可执行('X'在flag字段)。在这个节区,你可以看到我们main()函数的机器代码。$objdump-d-j.texttest实验结果:-d选项告诉objdump分解机器代码。-j告诉objdump只关心那个特定的节区(在本例中,是.text)。以下是执行命令后的部分内容。.data节区保存所有的初始化的变量,这些变量不在栈中。“Initialized”是指这些变量被赋于初始值,如”global_data”。那”local_data”呢?“local_data”的值不在此节区中,它们生活在进程的栈里。以下是用objdump查看.data节区:湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制8$objdump-d-j.datatest实验结果:C.查看programHeaderTable(PHT)段(segment)是一个OS“看懂”我们程序的方法。让我们看看我们程序是如何变成段的吧:$readelf-ltest实验结果:实验结果解释:映射很直观。例如段号2,这里有15个节区被映射到其中。.text节区就映射到此段。它的标志是R,E其含义分别是可读,可执行。W就是可读的含义。可以使用/proc/pid/maps文件也可以得看到它。pid是一个我们想要查看的进程的ID。,test进程运行的太快了,在进入/proc这前,它就结束了。可以使用gdb来解决此问题。也可以在return之前调用sleep()来搞定这个问题。湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制9在另一个控制台中:$gdbtest(gdb)bmainBreakpoint1at0x8048376(gdb)rBreakpoint1,0x08048376inmain()在此保持(hold)住,打开另一个控制台,找到test的PID。如果你想图省事的话,就这样:$cat/proc/`pgreptest`/maps实验结果:回到gdb,输入:(gdb)q湖北工业大学计算机学院网络工程系10网络网络工程系·2009年编制10于是,最后,我们看到了12个段(实际上是VMA)。重点关注第一个字段和最后一字段。第一字段显示了VMA的地址范围,最后一个字段显示了背后的文件。你在看到VMA的第8行与之前PHT的第2行的类似点了吗?不同之处是SHT说它自己于0x080484fc结束,但在8号段中我们看到它的结束地址是0x08049000。在VMA9号与段3号之间也有同样的现象。SHT显示3号段开始于0x080494fc。而VMA则显示开始于0x08049000。有这么几个因素我们必须了解:1.尽管VMA开始于不同的地址,与之关联的节区仍然被映射到精确的虚拟地址上了。2.内核分配内存是以4KB的页为基本单位的,所以每一页的地址都是4KB的整数倍。如0x1000,0x2000等。对于VMA的9号,这个页的地址是0x08049000。或从技术角度讲,这个段的地址必须与页面的大小对齐。最后,哪一个VMA是栈呢?VMA11就是。一般地,内核动态地分配几个页面,并映射到用户空间可能的最高的虚拟地址,这就是栈的区域了。简单地讲,每一个进程的地址空间被分成两部分(前提是32位的CPU):用户空间和内核空间。用户空间在0x00000000-0xc0000000,所以内核空间只能在0xc0000000以上了。于是,分配给栈的地址是在0xc0000000边界附近的。结束地址是固定的,开始地址可以根据保存内容的多少而变化。