Linux虛擬記憶體對映之brk/sbrk,map/munmap
一.關於虛擬記憶體
問題:
一個程式不能訪問另外一個程式的地址指向的空間.
理解:
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); //得到的地址是首地址+204
int *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);
}
/*輸出:
0x8909000
0x8909000
0x8909004
0x89090cc
0x89090cc
0x89090c8
15945
*/
應用案例:
寫一個程式查詢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