1. 程式人生 > >Linux虛擬記憶體對映之brk/sbrk,map/munmap

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