Linux虚拟内存映射之brk/sbrk,map/munmap

来源:互联网 发布:淘宝联盟是返利吗 编辑:程序博客网 时间:2024/06/05 23:46

一.关于虚拟内存

         问题:

                   一个程序不能访问另外一个程序的地址指向的空间.

         理解:

                   1.每个程序的开始地址ox8048000(?可由objdump 反汇编得到)

                   2.程序中使用的地址不是物理地址,而是逻辑地址(虚拟内存).

                     逻辑地址仅仅是编号.编号使用int 4字节整数表示.

                     4294967296=4G

                     每个程序提供了4G的访问能力(32位机,下同)

         问题:

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

         背景:

                   虚拟内存的提出:禁止用户直接访问物理存储设备.

                   有助于系统的稳定.

                                              

         结论:

                   虚拟地址与物理地址映射的时候有一个基本单位:至少会映射4K

                                     4k  1000 内存页.

                   段错误:无效访问. 那段内存没有映射

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

 

                   内存访问分两种:一个是可以访问,但不一定是合法的,比如malloc几个字节,

                   内存会给你映射4K空间,int*p=malloc(0); *(p+1000)=9999;理论说这是可以访问,但是非法的,它可能破坏维护malloc分配的数据结构,就跟虚表指针一样。

 

二.虚拟内存的分配

                   栈:编译器自动生成代码维护

                   堆:地址是否映射?映射的空间是否被管理?

1.brk/sbrk内存映射函数

分配释放内存:                

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

                            void *sbrk(int size);//返回空间地址

                            应用:

                                     1.使用sbrk分配空间

                                     2.使用sbrk得到没有映射的虚拟地址.

                                        第一次调用sbrk,sbrk(0)得到的是没有映射的虚拟首地址。

                                     3.使用brk分配空间

                                     4.使用brk释放空间

                            理解:

                                     sbrk(int  size)

                                     如果是第一次运行,则返回没有映射的空闲空间首地址,同时产生一个数据:指向地址

 

                                     sbrk与brk后台系统维护一个指针.

                                     指针默认是null.

                                    调用sbrk,判定指针是否是0,

 是:得到大块空闲空间的首地址初始化指针.同时把指针+size                               

                                         否:返回指针,并且把指针位置+size

demo:

#include <stdio.h>#include <unistd.h>main(){int *p=sbrk(0); //返回的是空闲空间的首地址,然后系统给映射一个页//*p=800;  //段错误int *p1=sbrk(4);//返回空闲地址,然后系统给映射4K  并修改指针为+size//先看一下指针是否为空,如果是空,就返回空闲空间的首地址,//然后再看里面的参数是几个字节,再看一下这几个字节是否有空间,//没空间的话就映射空间,然后把指针+4*(p1+10)=4000; //可以访问,反正系统给映射了4K空间大小,但是是非法的int *p2=sbrk(0);  //返回的是首地址+4  p2=sbrk(200);int *p3=sbrk(0); //得到的地址是首地址+204int *p4=sbrk(-4);//释放4个字节的空间int *p5=sbrk(-4);printf("%p\n",p);printf("%p\n",p1);printf("%p\n",p2);printf("%p\n",p3);printf("%p\n",p4);printf("%p\n",p5);printf("%d\n",getpid());/*int *p=sbrk(0);brk(p+1);//brk改变的是绝对位置*p=800;*/brk(p);//*p=99;//段错误//while(1);}/*输出:0x89090000x89090000x89090040x89090cc0x89090cc0x89090c815945*/

                            应用案例:

                                     写一个程序查找1-10000之间所有的素数.

                                     并且存放到缓冲,然后打印.

                                              

                                     缓冲的实现使用sbrk/brk

                                     流程:

                                               循环

                                                        判定是否素数(isPrimer)

                                                        是,分配空间存放

                                                        不是,继续下步.

#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}

2.mmap/munmap内存映射函数

没有任何额外维护数据的内存分配。

                   mmap(分配)/unmap(释放)

                   1.函数说明

                   void *mmap(

                            void *start,//指定映射的虚拟地址 0由系统指定开始位置)

                            size_t length,//映射空间大小pagesize倍数

                            int prot,//映射权限  PROT_NONE | PROT_READ PROT_WRITE PROT_EXEC

                            intflags,//映射方式

                            int fd,//文件描述符号

                            offset_t off);//文件中的映射开始位置(必须是pagesize的倍数)

                           

                            映射方式:

                                               内存映射:匿名映射。

                                               文件映射:映射到某个文件

                                                                                      只有文件映射最后两个参数有效。

                                              

                                               MAP_ANONYMOUS

                                               MAP_SHARED   MAP_PRIVATE(二选一)

2.demo

#include <unistd.h>#include <sys/mman.h>#include <stdlib.h>#include <stdio.h>main(){int *p=mmap(NULL,getpagesize(),PROT_READ,MAP_ANONYMOUS|MAP_SHARED,0,0);*p=20;*(p+1)=30;*(p+2)=40;printf("%d\n",p[2]);munmap(p,4096);}


三.总结:

智能指针(指针池)

                   STL                     

                   new          

                   malloc (小而多数据)

                   brk/sbrk (同类型的大块数据,动态移动指针)

                   mmap/munmap(控制内存访问/使用文件映射/控制内存共享)


                            异常处理

                                     int brk(void*)

                                     void *sbrk(int);

                                     如果成功.brk返回0   sbrk返回指针

                                     失败 brk返回-1  sbrk返回(void*)-1
0 0
原创粉丝点击