实验三 内存管理
实验三 内存管理
- 实验目的
1、 了解linux的内存管理机制和linux虚拟存储;
2、 学习使用内存分配函数完成对内存的分配和释放
3、 分析并实现与缺页相关的实验。
二、实验内容与要求
(一)编程使用vmalloc函数分配内容,并向内存中写入数据,再调用printf语句将写入的数据打印出来,最后调用free函数释放内存。据打印出来,最后调用free函数释放内存。
(二)查看stat文件
在linux系统中的/proc文件系统中有一个记录系统当前基本状况的文件stat。该文件中有一节是关于中断次数的。这一节中记录了从启动后到当前时刻发生的系统中断的总次数,,之后依次是0号中断发生的次数,1号中断发生的次数,依次类推。其中缺页中断是第14号中断,也就是在关键字intr之后的第16项。
(三)编写一个记录一段时间系统缺页次数的统计程序
可以利用stat文件提供的数据在一段时间的开始时刻和结束时刻分别读取缺页中断发生的次数,然后做一个简单的减法,就可以得出这段时间内发生的缺页中断次数。由于系统动态更新的,过去时间的数据无法采集到,所以这里的开始时刻最早也只能是当前时刻,实验采用的统计时间段就是从当前时刻开始的一段时间。
(四)知识引入
1、vmalloc()是内核可以用来分配连续虚拟内存、但非连续物理内存的方法。内核不应该使用标准c库链接并使用其malloc和free库的,这样会既笨拙又缓慢,因为这些函数要被从用户模式调用,因此内核有自己的内存操作函数。Kmalloc和kfree管理内核段内分配的内存,这是真实地址已知的实际物理内存块。vmalloc和vfree是对内核使用的虚拟内存进行分配和释放。Kmalloc返回的内存是物理的、连续的,更适合于类似设备驱动的程序来使用。但vmalloc能使用更多的资源,因为vmalloc还可以处理交换空间。
kmalloc分配在物理上连续的内存,这些内存是实际上存在的,并且是连续的,根据slab块分配。而vmalloc分配的内存在地址空间是连续的,但实际上在物理空间是不连续的,故必须更改页表来使物理地址和程序所使用的地址来使用,而通过kmalloc分配的地址由于上面所说的情况,同时注意到实际上物理地址在系统初始化时已经与页表对应好。
2、Linux内核中存在一个变量记录缺页中断次数,可以利用这个变量来统计一段时间内产生缺页中断的次数。用户可以指定统计的时间长度,也可以用默认的时间段长度。
三、实验步骤
1.实验1,创建文件first.c,编译,运行
2.实验2,切换目录proc再less stat
3.实验3,创建文件test2.c,编译,运行
四、程序清单:注意加注释(包含关键字、方法、变量等),在每个模块前加注释
(一)
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#define A_MEGABYTE 1024*1024
int main()
{
char *some_memory;
int megabyte=A_MEGABYTE;
int exit_code=EXIT_FAILURE;
some_memory=(char *)vmalloc(megabyte);/*申请内存*/
if(some_memory!=NULL)
{sprintf(some_memory,”hello world!\n”); /*将字符串写入some_memory所指向内存*/
printf(“s%”,some_momery);
free(some_memory); /*释放内存*/
printf(“memory is free!\n”);
exit_code=EXIT_SUCCESS;
}
exit(exit_code);
}
(二)
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define FILENAME "/proc/stat" /*指定文件操作的对象*/
#define DEFAULTTIME 5 /*设定缺省的统计时间段长度为5秒*/
static void sig_handler(int signo);
int get_page_fault(void);
int readfile(char *data);
int exit_flag=0;
int page_fault;
int main(int argc, char **argv)
{
struct itimerval v;
int cacl_time;
if (signal(SIGALRM, sig_handler) == SIG_ERR)
{
printf("Unable to create handler for SIGALRM\n");
return -1;
}
if (argc <=2 )
page_fault = get_page_fault();
/*初始化time_real*/
if (argc < 2)
{
printf("Use default time!\n");
cacl_time = DEFAULTTIME;
}
else if (argc == 2)
{
printf("Use user's time\n");
cacl_time = atoi(argv[1]);
}
else if (argc >2)
{
printf("Useage:mypage [time]\n");
return 0;
}
v.it_interval.tv_sec = cacl_time;
v.it_interval.tv_usec = 0;
v.it_value.tv_sec = cacl_time;
v.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &v, NULL);
while (!exit_flag);
printf("In %d secends,system calls %d page fault!\n", cacl_time, page_fault);
return 0;
}
static void sig_handler(int signo)
{
if(signo == SIGALRM) /*当ITIMER_REAL为0时,这个信号被发出*/
{
page_fault = page_fault - get_page_fault();
exit_flag = 1;
}
}
/*该函数调用文件操作函数readfile,得到当前系统的缺页中断次数*/
int get_page_fault(void)
{
char d[50];
int retval;
/*读取缺页中断次数*/
retval = readfile(d);
if (retval<0)
{
printf("read data from file failed!\n");
//exit(0);
return 0;
}
printf("Now the number of page fault is %s\n", d);
return atoi(d);
}
/*该函数对/proc/stat文件内容进行读操作,读取指定项的值*/
int readfile(char *data)
{
int fd;
int seekcount = 0;
int retval = 0;
int i=0;
int count = 0;
char c, string[50];
fd = open(FILENAME,O_RDONLY);
if (fd < 0)
{
printf("Open file /proc/stat failed!\n");
return -1;
}
/*查找stat文件中的关键字intr*/
do {
i = 0;
do {
lseek(fd, seekcount, SEEK_SET);
retval = read(fd, &c, sizeof(char));
if (retval < 0)
{
printf("read file error!\n");
return retval;
}
seekcount += sizeof(char);
if (c == ' ' || c == '\n')
{
string[i] = 0;
break;
}
if((c >= '0' && c<= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
string[i++] = c;
}while(1);
}while(strcmp("intr", string));
printf("find intr!\n");
/*读取缺页次数*/
do {
lseek(fd, seekcount, SEEK_SET);
retval = read(fd, &c, sizeof(char));
if(retval < 0)
{
printf("read file error!\n");
return retval;
}
seekcount += sizeof(char);
if (c == ' ' || c == '\n')
{
string[i] = 0;
i = 0;
count++;
}
if((c >= '0' && c<= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
string[i++] = c;
}while(count != 16);
close(fd);
strcpy(data, string);
return 0;
}
五、测试结果(运行结果、结果分析)
1.实验1
2.实验2
3.实验3
六、总结(实验效果分析、心得体会,遗留问题)
通过这次实验,我了解linux的内存管理机制和linux虚拟存储,学习使用内存分配函数完成对内存的分配和释放。虽然程序有一些报错,但是还是通过报错信息解决问题。同时我也明白了实际操作之前把理论知识学好在实验中才能得心应手,虽然会遇到各种问题但还是能通过知识解决问题。今后还是认真听讲该科目的内容,上课认真听讲,会避开很多报错。只是把程序运行一下是无法把知识掌握的,还是要花一点时间,认真读懂程序代码。