linux编程学习笔记(三) 虚拟内存映射 brk sbrk mmap umap

本文详细解释了程序间地址空间隔离的原因,介绍了内存映射的概念及其在操作系统中的作用,并通过sbrk、brk和mmap等函数的具体使用案例,展示了如何在Linux环境下分配和释放内存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原地址:http://blog.youkuaiyun.com/a8887396/article/details/8996213


1 问题: 一个程序为什么不能访问另外一个程序的地址指向的空间.

理解:
1.每个程序的开始地址0x80084000
2.程序中使用的地址不是物理,而是逻辑地址(虚拟内存).
逻辑地址仅仅是编号.编号使用int 4字节整数表示.
4294967296

每个程序提供了4G的访问能力


2 问题: 什么是内存映射? 什么是越界访问?为何出现段错误?

逻辑地址与物理地址关联才有意义:过程称为内存映射.

背景:
虚拟内存的提出:禁止用户直接访问物理存储设备.
有助于系统的稳定.

结论:
虚拟地址与物理地址映射的时候有一个基本单位:
4k字节  0x1000 1 内存页.
(malloc时 一次性最少映射一个页,这个范围内访问不会出现段错误)

段错误意味:地址没有映射到物理空间

越界访问: 比如malloc分配的空间之外的空间可以访问,但访问非法!

越界访问不一定会产生断错误

访问的虚拟内存地址没有与物理内存地址映射一定会出现段错误



3 虚拟内存的映射 

1 brk/sbrk 内存映射函数

补充: 帮助手册
man 节 关键字
1-8节
1:Linux系统(shell)指令  
2:系统函数  
3:标准C函数
7:系统编程帮助  man tcp ,man icmp ,man socket


分配释放内存:

void* sbrk(int increment) //返回空间地址
int brk(void *addr) //分配空间 释放空间
应用:
1 使用sbrk 分配空间
2 使用sbrk得到没有映射的虚拟地址
3 使用brk分配空间
4 使用brk释放空间


理解:
void* sbrk(int size)   //使用相对位置进行分配和释放
sbrk 与 brk 后台系统维护一个指针,增加这个指针相当与分配内存,减小这个指针相当与释放内存
指针默认是null。
调用sbrk,判断指针是否是0 ,是:1初始化指针(一页的起始地址) 2返回指针
3同时把指针+size(若此地址未映射,则先映射一页空间)
,否:1返回指针  2 指针位置+size
sbrk(a) 用于分配a字节的空间, 返回值是这个空间的起始地址
sbrk(-a) 用于释放a字节的空间
sbrk(0) 用于取得目前指针的位置
失败返回 (void *)(-1)


int brk(void *addr) //使用绝对地址进行分配和释放

将指针设置在addr,addr以前空间都被分配出来。addr一般通过sbrk(0)来获得
若未映射则先映射
失败返回-1

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3.   
  4. int main()  
  5. {  
  6.     int *p1 = sbrk(4); // 返回空闲地址 内部指针+4  
  7.     int *p2 = sbrk(200);// 返回内部指针 内部指针+200  
  8.     int *p3 = sbrk(0); //返回内部指针  
  9.       
  10.     printf("%p\n",p1);  
  11.     printf("%p\n",p2);  
  12.     printf("%p\n",p3);  
  13.     /* 
  14.     0x84fb000 
  15.     0x84fb004 
  16.     0x84fb0cc 
  17.     */    
  18.     printf("pid:%d\n",getpid());  
  19.     while(1) {}  
  20. }  


[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3.   
  4. int main()  
  5. {  
  6.   
  7.     int *p1 = sbrk(0); // 返回空闲地址  没分配地址  
  8.     brk(p1+100); //分配一个空间:发现是未映射的,先映射一个页,再分配100字节(参数是分配空间的结束地址)  
  9.   
  10.     *(p1+100) = 80;  
  11.     *(p1+1000) = 800; // 越界访问也是可以的  
  12.       
  13.     brk(p1+1); //将分配的空间的尾地址设置为p1+1  
  14.     *(p1+100) = 99; //越界访问仍然可以  
  15.       
  16.     brk(p1); //继续释放,将分配的空间的尾地址设置为p1 因为这个页里面分配0空间,这个页不再被映射  
  17.     *(p1) = 100; //段错误 地址未映射  
  18.       
  19.   
  20.       
  21. }  



[cpp]  view plain copy
  1. /* 
  2.  找出1-10000中的素数,存在内存中,最后再打印出来。 
  3. */  
  4.   
  5.   
  6. #include <stdio.h>  
  7. #include <unistd.h>  
  8. #include <math.h>  
  9.   
  10. int main()  
  11. {  
  12.     int *p_start ,*p_end;  
  13.     p_start = sbrk(0);  
  14.     p_end = p_start;  
  15.     int i,j;  
  16.     int is_sushu;  
  17.       
  18.     for(i = 2; i < 1001; i++)  
  19.     {  
  20.         is_sushu = 1;  
  21.         for( j=2; j<sqrt(i); j++)  
  22.         {  
  23.             if( i%j ==0 )  
  24.             {  
  25.                 is_sushu = 0;  
  26.                 break;  
  27.             }  
  28.         }  
  29.             if(is_sushu)  
  30.             {  
  31.                 brk(p_end+1);  
  32.                 *p_end = i;  
  33.                 p_end +=1;  
  34.             }  
  35.     }  
  36.       
  37.           
  38.     int *p = p_start;  
  39.     while(p!= p_end)  
  40.     {  
  41.         printf("%d ",*p);  
  42.         p++;  
  43.     }  
  44.       
  45.     brk(p_start);  
  46.     printf("\n");  
  47.   
  48.       
  49. }  






mmap( 分配)/umap(释放)

1函数说明
  void *mmap(
void *start, //指定映射的虚拟地址  如为0 系统指定开始位置
size_t length, //映射的空间大小 : pagesize倍数
int prot,//映射权限 PROT_NONE PROT_READ PROT_WRITE PROT_EXEC
int flags,//映射方式
int fd,//文件描述符
offset_t  off); //文件中的偏移位置(必须是page_size的倍数)
       int munmap(void *addr, size_t length);


       
       映射方式:
内存映射:匿名映射
文件映射:映射到文件 ,只有当文件映射时,最后两个参数才有效


MAP_ANONYMOUS 写了就是内存映射 不写就是文件映射
MAP_PRIVATE MAP_SHARED 2选1


  umap(void *start,size_t lenth)


[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <sys/mman.h>  
  3. #include <stdlib.h> //NULL宏  
  4. #include <unistd.h> //getpagesize()  
  5.   
  6. main()  
  7. {  
  8.       
  9.     int *p =mmap(  
  10.         NULL,  
  11.         getpagesize(),  
  12.         PROT_READ|PROT_WRITE, //只写WRITE时可以读,只写READ时不可以写 段错误  
  13.         MAP_ANONYMOUS|MAP_SHARED,  
  14.         0,0);  
  15.     *p = 20;  
  16.     *(p+1) = 30;  
  17.     *(p+2) = 40;  
  18.       
  19.     printf("%d\n",p[2]); //40  
  20.       
  21.     printf("%p\n",p);  
  22.     munmap(p,4096);  
  23.   
  24.     printf("pid:%d\n",getpid());  
  25.     while(1){}    
  26. }  



3总结

智能指针
最方便使用STL new
STL
new
malloc  小而多的数据
效率最高:brk mmap
brk/sbrk 同类型的大块数据,根据需要动态移动指针
mmap/munmap 控制内存访问 内存直接向使用文件映射 控制内存共享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值