Linux——虚拟内存

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 20:47   2314   0

问题的提出

pro1.c

#include <stdio.h>
#include <stdlib.h>
main()
{
 int *a=malloc(4);
 *a=9999;
 //*(a+1)=1000;
 //*(a+1000)=10000;
 printf("%p\n",a);
 while(1);
}

gcc pro1.c -omain1 运行 main1 结果:0x8a01008


pro2.c

#include <stdio.h>
#include <stdlib.h>
main()
{
 int *a=(int*)0x8a01008;//逻辑地址 没有与之相对应的物理地址 要建立关联才有意义 这个过程就是内存映射
 printf("%d\n",*a);
 while(1); 
}

猜会不会打印9999

gcc pro2.c -omain2 运行 main2 结果:段错误

原因:
一个程序不能访问另外一个程序的地址指向的空间.
理解:
1.每个程序的开始地址0x80084000
2.程序中使用的地址不是物理地址,而是逻辑地址(虚拟内存).
逻辑地址仅仅是编号.编号使用int 4字节整数表示.
4294967296=4G
每个程序提供了4G的访问能力
问题:
逻辑地址与物理地址关联才有意义:过程称为内存映射.

结论:
虚拟地址与物理地址映射的时候有一个基本单位:至少会映射4K
4k 1000 内存页.
段错误:无效访问. 那段内存没有映射
非合法访问:比如malloc分配的空间之外的空间可以访问(没有段错误),但访问非法.因是越界访问

内存访问分两种:一个是可以访问,但不一定是合法的,比如malloc几个字节,
内存会给你映射4K空间,int* p=malloc(0); *(p+1000)=9999;理论说这是可以访问

四。虚拟内存的分配
栈:编译器自动生成代码维护,我们不用关心
堆:我们关心地址是否映射,映射的空间是否被管理。
1.brk/sbrk 内存映射函数


补充:帮助手册
man 节 关键字
1-8 1:Linux系统(shell)指令 man 1 ls;

2:系统函数 man 2 brk;
3:标准C函数 man fopen 一般在2和3节找

7:系统编程帮助 man 7 tcp(icmp;udp;socket)

分配释放内存:
int brk(void *end);//分配空间,释放空间

void *sbrk(int size);//返回空间分配前的地址 然后内存内部当前指针移动size

应用:
1.使用sbrk分配空间 sbrk(非零整数)
2.使用sbrk得到没有映射的虚拟地址.第一次调用sbrk,sbrk(0)得到的是没有映射的虚拟首地址。
3.使用brk分配空间
4.使用brk释放空间

brk.c

#include <stdio.h>
#include <unistd.h>

main()
{
 /*int *p=sbrk(0);没有映射空间的虚拟地址
 *p=8888;*/ //会出现段错误
 int *p1=sbrk(4);//分配4个字节 映射了一个页 内部当前指针移动4字节
 *p1=8888;
 //*(p+1024)=7777;//段错误
 *(p1+1023)=7777;//没有段错误
  
 printf("%d\n",*p1);
 
}


应用案例:
写一个程序查找1-10000之间所有的素数.见demo1.c
并且存放到缓冲,然后打印.

缓冲的实现使用sbrk/brk
流程:
循环
判定是否素数(isPrimer)
是,分配空间存放
不是,继续下步.

demo.c

#include <stdio.h>
#include <unistd.h>
int isPrimer(int a)
{ 
 int i;
 for(i=2;i<a;i++)
 {
  if(a%i==0)
  {
   return 1;   
  }
 }
 return 0;
}

main()
{
 int i=2;
 int b;
 int *r;
 int *p;
 p=sbrk(0);
 r=p;
 for(;i<100;i++)
 {
  b=isPrimer(i);
  if(b==0)
  {
   brk(r+1);
   *r=i;
   r=sbrk(0);
  }
 }
 
 i=0;
 r=p;
 while(r!=sbrk(0))
 {
  printf("%d\n",*r);
  r++;
 }
 brk(p);//free
 
}


总结:
智能指针
stl
new
malloc
brk/sbrk比较适合大空间
异常处理
int brk(void*)
void *sbrk(int);
如果成功.brk返回0 sbrk返回指针
失败 brk返回-1 sbrk返回(void*)-1

memerr.c

#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
extern int errno;
int main()
{
 void *p=sbrk(1000000000*3);
 if(p==(void*)-1)
 {
  //perror("Hello:");
  //printf("Memory:%m\n");
  printf("::%s\n",strerror(errno));
 }
 
}


Unix函数错误,修改内部变量:errno

字符串函数string.h cstring
内存管理函数malloc memset mamcmp memcpy ...
bzero
错误处理函数
标准IO函数
时间函数
类型转换函数

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP