【操作系统】LinuxFedora13当new一个新内存空间的时候操作系统如何分配
来源:互联网 发布:pcm-d50淘宝 编辑:程序博客网 时间:2024/05/16 04:54
C和C++程序上的内存分配释放函数如下:
cat /proc/pids/maps命令
cat /proc/pid/status命令
====================================================================================
① 首先尝试申请一个128MB空间,观察maps和status文件的变化。
#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>using namespace std;//命令 cat /proc/pid/mapsvoid maps(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/maps"};strcat(str,l);cout<<str<<endl;system(str);}//命令 cat /proc/pid/statusvoid status(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/status"};strcat(str,l);cout<<str<<endl;system(str);}int main(){int *p[8];char s[8];int pid = getpid();sprintf(s,"%d",pid);cout<<"分配内存前的maps和status情况"<<endl;maps(s);status(s);cout<<"先分配1个128MB的内存"<<endl;//一个int占4个字节//128MB = 128 * 1024 KB = 131072 KB//128MB = 128 * 1024 * 1024 字节(byte) = 134217728 Byte//int数组长度为 128 * 1024 * 1024 / 4p[1] = new int[33554432];maps(s);status(s);delete[] p[1];return 0;}创建128MB内存前后程序执行命令cat /proc/pid/maps,发现maps信息中有一个地址段发生变化。
b7848000 (16) – af847000 (16) = 134221824(10) =128MB + 4KB
创建128MB内存程序前后执行命令cat/proc/pid/status,发现status信息有变化
VmPeak进程地址空间大小增加了131016KB = 128MB– 56KB
VmSize进程虚拟地址空间的大小增加了131076KB= 128MB + 4KB
VmHWM程序得到分配到物理内存的峰值,文件内存映射和匿名内存映射的大小增加了36KB
VmRSS应用程序正在使用的物理内存的大小增加了36KB
VmData程序数据段的大小增加了131076KB= 128MB + 4KB
VmPTE该进程的页表的大小增加了4KB
voluntary_ctxt_swicthes进程主动切换的次数增加了2次
② 连续申请分配六个128MB空间(记为1~6号),然后释放第2、3、5号的128MB空间。
<span style="font-size:12px;">#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>using namespace std;//命令 cat /proc/pid/mapsvoid maps(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/maps"};strcat(str,l);cout<<str<<endl;system(str);}//命令 cat /proc/pid/statusvoid status(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/status"};strcat(str,l);cout<<str<<endl;system(str);}int main(){int *p[8];char s[8];int pid = getpid();sprintf(s,"%d",pid);cout<<"分配内存前的maps和status情况"<<endl;maps(s);status(s);cout<<"先分配6个128MB的内存,然后删除235号"<<endl;//一个int占4个字节//128MB = 128 * 1024 KB = 131072 KB//128MB = 128 * 1024 * 1024 字节(byte) = 134217728 Byte//int数组长度为 128 * 1024 * 1024 / 4p[0] = new int[33554432];p[1] = new int[33554432];p[2] = new int[33554432];p[3] = new int[33554432];p[4] = new int[33554432];p[5] = new int[33554432];delete[] p[1];delete[] p[2];delete[] p[4];maps(s);status(s);delete[] p[0];delete[] p[3];delete[] p[5];return 0;}</span><span style="font-size: 24px;"></span>
6号128MB内存段(存在):
8f781000(16) – 87780000(16)= 134221824(10) B = 128MB + 4KB
5号128MB内存段(释放):
97782000(16) – 8f781000(16)= 134221824(10) B = 128MB + 4KB
4号128MB内存段(存在):
9f783000(16) – 97782000(16)= 134221824(10) B = 128MB + 4KB
3号和2号128MB内存段(释放):
af785000(16) - 9f783000(16)= 268443648(10) B = 2 * (128MB + 4KB)
1号128MB内存段(存在):
b7788000(16) – af785000(16)= 134230016(10) B = (128MB + 4KB) + 8MB
存在的内存段:
6号128MB内存段:87780000-8f781000
4号128MB内存段:97782000-9f783000
1号128MB内存段:af785000-b7788000
VmPeak进程地址空间大小增加了786396KB = 128 MB*6 – 36 KB
VmSize进程虚拟地址空间的大小增加了393228KB = 128 MB * 3 + 12KB
VmHWM文件内存映射和匿名内存映射的大小增加了56KB
VmRSS应用程序正在使用的物理内存的大小增加了44KB
VmData程序数据段的大小增加了393228KB = 128 MB * 3 + 12KB
VmPTE该进程的页表的大小增加了20KB
voluntary_ctxt_swicthes进程主动切换的次数增加了2次
③ 连续申请分配六个128MB空间(记为1~6号),释放第2、3、5号的128MB空间,然后再分配1024MB。
<span style="font-size:12px;">#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>using namespace std;//命令 cat /proc/pid/mapsvoid maps(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/maps"};strcat(str,l);cout<<str<<endl;system(str);}//命令 cat /proc/pid/statusvoid status(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/status"};strcat(str,l);cout<<str<<endl;system(str);}int main(){int *p[8];char s[8];int pid = getpid();sprintf(s,"%d",pid);cout<<"分配内存前的maps和status情况"<<endl;maps(s);status(s);cout<<"先分配6个128MB的内存,然后删除235号"<<endl;//一个int占4个字节//128MB = 128 * 1024 KB = 131072 KB//128MB = 128 * 1024 * 1024 字节(byte) = 134217728 Byte//int数组长度为 128 * 1024 * 1024 / 4p[0] = new int[33554432];p[1] = new int[33554432];p[2] = new int[33554432];p[3] = new int[33554432];p[4] = new int[33554432];p[5] = new int[33554432];delete[] p[1];delete[] p[2];delete[] p[4];//1024MB = 128MB * 8cout<<"分配一个1024MB内存..."<<endl;p[6] = new int[33554432*8];maps(s);status(s);delete[] p[0];delete[] p[3];delete[] p[5];delete[] p[6];return 0;}</span><span style="color: rgb(255, 0, 0);font-size:24px;"></span>
6号128MB内存段和1024MB内存段(存在):
8f8dd000 – 478db000 = 1207967744= 128MB + 4KB + 1024MB + 4 KB
5号128MB内存段(已释放):
978de000 – 8f8dd000 =134221824 = 128MB + 4KB
4号128内存段(存在):
9f8df000 – 978de000 = 134221824= 128MB + 4KB
3号和2号128MB内存段(已释放):
af8e1000 – 9f8df000 =268443648 = 2 * (128MB + 4KB)
1号128MB内存段(存在):
b78e4000 – af8e1000 = 134230016= (128MB + 4KB) + 8MB
其它变量:
b78f3000 – b78e4000 = 61440 =60KB
b78f5000 – b78f3000 = 8192 = 8KB
VmPeak进程地址空间大小增加了
1441748KB = 128 MB *3 +1024MB– 44 KB
VmSize进程虚拟地址空间的大小增加了
1441808KB = 128 MB * 3 +1024MB + 16KB
VmHWM程序得到分配到物理内存的峰值,文件内存映射和匿名内存映射的大小增加了56KB
VmRSS应用程序正在使用的物理内存的大小增加了48KB
VmData程序数据段的大小增加了
1441808KB = 128 MB * 3 +1024MB + 16KB
VmPTE该进程的页表的大小增加了24KB
voluntary_ctxt_swicthes进程主动切换的次数增加了2次
④ 比较三次结果:
推测:再添加64MB,这64MB会放在128MB+1024MB的内存段后面。
⑤ 连续申请分配六个128MB空间(记为1~6号),释放第2、3、5号的128MB空间,分配1024MB。再分配64M内存。
#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>using namespace std;//命令 cat /proc/pid/mapsvoid maps(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/maps"};strcat(str,l);cout<<str<<endl;system(str);}//命令 cat /proc/pid/statusvoid status(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/status"};strcat(str,l);cout<<str<<endl;system(str);}int main(){int *p[8];char s[8];int pid = getpid();sprintf(s,"%d",pid);cout<<"分配内存前的maps和status情况"<<endl;maps(s);status(s);cout<<"先分配6个128MB的内存,然后删除235号"<<endl;//一个int占4个字节//128MB = 128 * 1024 KB = 131072 KB//128MB = 128 * 1024 * 1024 字节(byte) = 134217728 Byte//int数组长度为 128 * 1024 * 1024 / 4p[0] = new int[33554432];p[1] = new int[33554432];p[2] = new int[33554432];p[3] = new int[33554432];p[4] = new int[33554432];p[5] = new int[33554432];delete[] p[1];delete[] p[2];delete[] p[4];//1024MB = 128MB * 8cout<<"分配一个1024MB内存..."<<endl;p[6] = new int[33554432*8];//64MB = 128MB / 2cout<<"分配一个64MB的内存..."<<endl;p[7] = new int[33554432/2];maps(s);status(s);delete[] p[0];delete[] p[3];delete[] p[5];delete[] p[6];delete[] p[7];return 0;}
6号128MB内存段+1024MB内存段
8f709000 – 47707000 = 1207967744= 128MB + 4KB + 1024MB + 4 KB
4号128MB内存段
9f70b000 – 9770a000 = 134221824= 128MB + 4KB
1号128MB内存段+ 64MB内存段
b7710000 – ab70c000 = 201342976= 128MB + 8KB +64MB + 8KB
由此发现前面的推测错误,实际上是使用首次适应算法来创建新的内存段。
1. 因为1号和4号内存段之间有2、3号两个128MB的内存段,总计256MB内存段。4号到6号之间有5号一个内存 段,共128MB内存段。2. 由于1024MB大于23号的256MB也大于5号的128MB,所以放在6号之后了。
3. 而64MB在碰到23号的256MB刚好合适,所以就直接放入这块了。
4. 如果是最佳适应算法64MB应该是放在5号的128MB内存段,而不是23号的256MB。
VmPeak进程地址空间大小增加了
1507288 KB = 128 MB *3+1024MB + 64MB – 40 KB
VmSize进程虚拟地址空间的大小增加了
1507348 KB = 128 MB * 3 +1024MB + 64MB + 20KB
VmHWM程序得到分配到物理内存的峰值,文件内存映射和匿名内存映射的大小增加了56 KB
VmRSS应用程序正在使用的物理内存的大小增加了52 KB
VmData程序数据段的大小增加了
1507348 KB = 128 MB * 3 +1024MB + 64MB + 20KB
VmPTE该进程的页表的大小增加了28 KB
voluntary_ctxt_swicthes进程主动切换的次数增加了2次
四次结果进行比较:
结论:
====================================================================================
⑥ 设计一个程序测试出你的系统单个进程所能分配到的最大虚拟内存空间为多大。
#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>using namespace std;//命令 cat /proc/pid/mapsvoid maps(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/maps"};strcat(str,l);cout<<str<<endl;system(str);}//命令 cat /proc/pid/statusvoid status(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/status"};strcat(str,l);cout<<str<<endl;system(str);}int main(){int *p[10000] = { NULL };char s[8];int pid = getpid();sprintf(s,"%d",pid);cout<<"分配内存前的maps和status情况"<<endl;maps(s);status(s);int i = 0;try{do{p[i] = new int[33554432];}while(i<10000 && p[i++]!=NULL);}catch(std::bad_alloc&){cout<<"耗光虚拟内存后的maps和status情况 "<<i<<endl;maps(s);status(s);int max = i-1;for(i=-1;++i<max;){delete[]p[i];}}return 0;}
VmPeak进程地址空间大小增加了
2885660KB ≈2.751979827880859375 GB
VmSize进程虚拟地址空间的大小增加了
2884696KB ≈ 2.75106048583984375GB
VmHWM程序得到分配到物理内存的峰值,文件内存映射和匿名内存映射的大小增加了212KB
VmRSS应用程序正在使用的物理内存的大小增加了212KB
VmData程序数据段的大小增加了
2884696KB = 2.75106048583984375 GB
VmPTE该进程的页表的大小增加了88KB
voluntary_ctxt_swicthes进程主动切换的次数增加了2次
分配到的虚拟内存空间的最大峰值VmPeak是:
2888780 KB ≈2.754955291748046875 GB
实际上使用的虚拟内存大小VmSize是
2887756 KB ≈2.753978729248046875 GB
所以当前系统,单个进程所能分配到的最大虚拟内存空间约为 2.75 GB
而该Linux虚拟机的设定内存大小是2 GB。
====================================================================================
⑦ 编写一个程序,分配256MB内存空间(或其他足够大的空间),检查分配前后/proc/pid/status文件中关于虚拟内存和物理内存的使用情况,然后每隔4KB间隔将相应地址进行读操作,再次检查/proc/pid/status文件中关于内存的情况,对比前后两次内存情况,说明所分配物理内存(物理内存块)的变化。然后重复上面操作,不过此时为写操作,再观察其变化。
一、读操作
<span style="font-size:12px;">#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>using namespace std;//命令 cat /proc/pid/mapsvoid maps(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/maps"};strcat(str,l);cout<<str<<endl;system(str);}//命令 cat /proc/pid/statusvoid status(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/status"};strcat(str,l);cout<<str<<endl;system(str);}int main(){int *p;char s[8];int pid = getpid();sprintf(s,"%d",pid);//一个int占4个字节//128MB = 128 * 1024 KB = 131072 KB//128MB = 128 * 1024 * 1024 字节(byte) = 134217728 Byte//int数组长度为 128 * 1024 * 1024 / 4//256MB = 128M * 2cout<<"分配256MB内存,看maps和status的情况..."<<endl;int sum = 33554432 * 2;p = new int[sum];status(s);cout<<"进行读操作"<<endl;//相隔4KB进行读写就是相隔1024个int进行读写int i = 0;for(;i<sum;i += 1024){p[i];}cout<<endl;status(s);delete[] p;return 0;}</span><span style="font-size: 24px;"></span>
发现Vm内存没有变化。voluntart_ctxt_switches加1.
二、写操作:
#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>using namespace std;//命令 cat /proc/pid/mapsvoid maps(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/maps"};strcat(str,l);cout<<str<<endl;system(str);}//命令 cat /proc/pid/statusvoid status(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/status"};strcat(str,l);cout<<str<<endl;system(str);}int main(){int *p;char s[8];int pid = getpid();sprintf(s,"%d",pid);//一个int占4个字节//128MB = 128 * 1024 KB = 131072 KB//128MB = 128 * 1024 * 1024 字节(byte) = 134217728 Byte//int数组长度为 128 * 1024 * 1024 / 4//256MB = 128M * 2cout<<"分配256MB内存,看maps和status的情况..."<<endl;int sum = 33554432 * 2;p = new int[sum];status(s);cout<<"进行写操作"<<endl;//相隔4KB进行读写就是相隔1024个int进行读写int i = 0;for(;i<sum;i += 1024){p[i] = i;}cout<<endl;status(s);delete[] p;return 0;}
VmHWM程序得到分配到物理内存的峰值,文件内存映射和匿名内存映射的大小增加了261900KB =256 MB – 244 KB
VmRSS应用程序正在使用的物理内存的大小增加了261900KB
VmPTE该进程的页表的大小增加了508KB
voluntary_ctxt_swicthes进程主动切换的次数增加了1次
nonvoluntary_ctxt_switches进程被动切换的次数增加了32次
将写操作指向的地址输出来:
添加以下代码:
void statusvmHWM(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[] = {"/status | grep VmRSS"};strcat(str,l);system(str);}修改成以下代码:
int i = 0;for(;i<sum;i+=1024){p[i] = 1;statusvmHWM(s);sleep(1);}
运行结果:
发现每写一次,VmRSS增加4KB,VmHWM也一样,它们最终的值也一样。
修改循环,间隔4096个int,即16KB的间隔进行读取。
for(;i<sum;i+=4096){ /*…*/ }
运行结果:
VmHWM程序得到分配到物理内存的峰值,文件内存映射和匿名内存映射的大小增加了65544KB =64 MB + 8 KB
VmRSS应用程序正在使用的物理内存的大小增加了65544KB
VmPTE该进程的页表的大小增加了508KB
voluntary_ctxt_swicthes进程主动切换的次数增加了1次
nonvoluntary_ctxt_switches进程被动切换的次数增加了12次
====================================================================================⑧ 编写并运行(在第5步的程序未退出前)另一进程,分配等于或大于物理内存的空间,然后每隔4KB间隔将相应地址的字节数值增1,此时再查看前一个程序的物理内存变化,观察两个进程竞争物理内存的现象。
#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <time.h>using namespace std;//命令 cat /proc/pid/mapsvoid maps(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/maps"};strcat(str,l);cout<<str<<endl;system(str);}//命令 cat /proc/pid/statusvoid status(char s[8]){char str[100] = {"cat /proc/"};strcat(str,s);char l[8] = {"/status"};strcat(str,l);cout<<str<<endl;system(str);}void statusvmHWM(char s[8]){char str[100] = {"echo '('$(date +%H:%M:%S)')' $(cat /proc/"};strcat(str,s);char l[] = {"/status | grep VmHWM)"};strcat(str,l);system(str);}int main(){int *p;char s[8];int pid = getpid();sprintf(s,"%d",pid);int sum = 2.74 * 1024 * 1024 * 1024 / 4;p = new int[sum];//相隔4KB进行读写就是相隔1024个int进行读写int i = 0;for(;i<sum;i += 1024){p[i]++;}delete[] p;return 0;}
先运行本题程序再运行五题程序
本题程序输出结果
nonvoluntary_ctxt_switches进程被动切换的次数增加了1394
第五题程序(没有进程竞争)和本题程序(有进程竞争)的比较:
nonvoluntary_ctxt_switches进程被动切换的次数多了1383
==================================================================
⑨ 分配足够大的内存空间,其容量超过系统现有的空闲物理内存的大小,1)按4KB的间隔逐个单元进行写操作,重复访问数遍(使得程序运行时间可测量);2)与前面访问总量和次数不变,但是将访问分成16个连续页为一组,逐组完成访问,记录运行时间。观察系统的状态,比较两者运行时间,给出判断和解释。
代码一、
#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <sys/time.h>using namespace std;int main(){timeval starttime,endtime;int *p;char s[8];int pid = getpid();sprintf(s,"%d",pid);int sum = 2.74 * 1024 * 1024 * 1024 / 4;p = new int[sum];//相隔4KB进行读写就是相隔1024个int进行读写int i,j;gettimeofday(&starttime,0);for(i=0;i<sum;i += 1024){p[i]++;}gettimeofday(&endtime,0);double timeuse = 1000000*(endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;timeuse /=2000;//mscout<<timeuse<<"ms"<<" = "<<timeuse/1000<<"s"<<endl;delete[] p;return 0;}代码二、
#include <iostream>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <pthread.h>#include <sys/time.h>using namespace std;int sum = 2.74 * 1024 * 1024 * 1024 / 4;int *p = new int[sum];;int a = 0;void* visit(void* arg){int i = *(int *)arg;int end = i + sum/16;for(;i < end;i += 1024){++p[i];}++a;}int main(){timeval starttime,endtime;pthread_t id[16];int i,ret;int pc[16];int x = sum /16;for(i=-1;++i<16;){pc[i] = i * x;}char s[8];int pid = getpid();sprintf(s,"%d",pid);cout<<"进入计时状态"<<endl;gettimeofday(&starttime,0);for(i=-1;++i<16;){ ret=pthread_create(&id[i],NULL,visit,&pc[i]);}while(a!=16){}gettimeofday(&endtime,0);cout<<"结束计时状态"<<endl;double timeuse = 1000000*(endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;timeuse /=1000;//mscout<<timeuse<<"ms"<<" = "<<timeuse/1000<<"s"<<endl;delete[] p;return 0;}代码一结果:
代码二结果:
代码1是顺序访问数组,代码2是将数组切割成十六份,每份由一个线程负责访问,总共十六个线程。
代码2比代码1慢。- 【操作系统】LinuxFedora13当new一个新内存空间的时候操作系统如何分配
- 操作系统-内存管理-内存空间的连续分配方式
- C++new分配内存空间
- 操作系统的内存分配
- 关于新写一个操作系统的讨论
- 操作系统执行可执行程序时,内存是如何分配的?
- 如何写一个最简单的操作系统
- 如何写一个最简单的操作系统
- 操作系统的内存分配问题
- 将“操作系统”当“高级C语言”如何?
- XP 真的是一个新的操作系统么?
- 在线操作系统---一个即将颠覆互联网模式的新宠儿
- 在线操作系统---一个即将颠覆互联网模式的新宠儿
- 32位操作系统寻址范围与支持的最大内存空间
- 一个简单的操作系统
- 一个小型的操作系统
- 一个操作系统的实现
- 当new失败时候
- autorelease自动释放池
- hihocoder 1032
- eclipse下的android开发环境突然崩溃
- Mongodb操作
- java web一HTTP协议
- 【操作系统】LinuxFedora13当new一个新内存空间的时候操作系统如何分配
- pptpd vpn的配置
- Yocto tips (2): Yocto Linux内核编译目录在哪?
- 【蓝桥第二周】01背包问题
- 算法的上帝——Donald E.Knuth
- 我的六级之路
- .globl _start 含义
- File学习
- KUbuntu/Ubuntu 14.04 (降级)安装 SVN 1.7&&Ubuntu14.10安装subversion1版本