虚拟内存
问题:
一个程序不能访问另外一个程序的地址指向的空间.
理解:
1.每个程序的开始地址0x80084000
2.程序中使用的地址不是物理,而是逻辑地址(虚拟内存).
逻辑地址仅仅是编号.编号使用int 4字节整数表示.
4294967296
每个程序提供了4G的访问能力
问题:
逻辑地址与物理地址关联才有意义:过程称为内存映射.
背景:
虚拟内存的提出:禁止用户直接访问物理存储设备.
有助于系统的稳定.
结论:
虚拟地址与物理地址映射的时候有一个基本单位:
4k 1000 内存页.
段错误:无效访问.
合法访问:比如malloc分配的空间之外的空间可以访问,但访问非法.
虚拟内存的分配.
栈:编译器自动生成代码维护
堆:地址是否映射,映射的空间是否被管理.
1.brk/sbrk内存映射函数
分配释放内存:
intbrk(void *end);//分配空间,释放空间
void*sbrk(int size);//返回空间地址
应用:
1.使用sbrk分配空间/size为正 分配空间 size为负 可释放空间
2.使用sbrk得到没有映射的虚拟地址.
3.使用brk分配空间
4.使用brk释放空间
理解:
sbrk(int size)
sbrk与brk后台系统维护一个指针.
指针默认是null.
调用sbrk,判定指针是否是0,是:得到大块空闲空间的首地址初始化指针.同时把指针+size
否:返回指针,并且把指针位置+size
例子:Linux下
代码1:
#include<stdio.h>
#include<unistd.h>
void main()
{
int * p1=sbrk(0); //得到大块空闲空间的首地址初始化指针
int * p2=sbrk(4); //分配4个字节的空间先返回空闲空间的首地址,在将指针加4
int * p3=sbrk(4); //同理,返回的指针地址为上一次sbrk返回的地址+size
printf(“%p\n”,p1);
printf(“%p\n”,p2);
printf(“%p\n”,p3);
}
运行结果:
0x9d9d000 sbrk(0)返回的空闲空间首地址
0x9d9d000 sbrk(0)返回的空间地址,并把地址+size(0x9d9d004)0x9d9d000-0x9d9d004为sbrk(4)分配的4个字节的空间
0x9d9d004 再次调用sbrk(4),返回的指针为地址0x9d9d004,指针再次+size
0x9d9d004-0x9d9d008为这次调用sbrk分配的4个字节的空间
代码2:
#include<stdio.h>
#include<unistd.h>
void main()
{
int* p=sbrk(0); //返回空闲空间的首地址,但系统并没有给虚拟内存映射物理内存
*p=800; //会出现段错误,无法访问p指向的地址的空间
brk(p+1); //brk(p+1) 是把p指针向后移了4个字节,系统把虚拟内存映射到了//物理内存(映射了一个页的物理内存4k),brk分配了4个字节的//动态内存空间
*p=800; //不会出现段错误
brk(p); //brk(p)又把指针向回移了4个字节,释放了4个字节的空间
*p=800; //则不能再访问p的空间
}
应用案例:
写一个程序查找1-10000之间所有的素数.
并且存放到缓冲,然后打印.
缓冲的实现使用sbrk/brk
流程:
循环
判定是否素数(isPrimer)
是,分配空间存放
不是,继续下步.
代码:
#include<stdio.h>
#include<unistd.h>
int isprimer(int a)
{
intI;
for(i=2;i<a;i++)
{
if(a%i==0)
return 1;
else
return 0;
}
}
void main()
{
int i=2;
int *p=sbrk(0);
int *r;
r=p;
for(;i<1000;i++)
{
if(isprimer(i)==0)
{
brk(r+1);
*r=i;
r=sbrk(0);
}
}
r=p;
while(r!=sbrk(0))
{
printf(“%d\n”,*r);
r++
}
}
brk(p); //free
brk/sbrk
异常处理
intbrk(void*)
void*sbrk(int);
如果成功.brk返回0 sbrk返回指针
失败 brk返回-1 sbrk返回(void*)-1