導航:首頁 > 源碼編譯 > 編譯器如何請求操作系統分配空間

編譯器如何請求操作系統分配空間

發布時間:2023-05-25 08:52:04

1. c語言 vc編譯器 結構體函數分配空間 比如struct stu*p;p=(struct stu*

請猜薯亮出代碼,才能說清楚
一般,在子函數中申請岩中的變數空間,要通過指針變數 帶回穗棗者到主函數中,才能使用。

2. 操作系統執行可執行程序時,內存分配是怎樣的

在操作系統中,一個進程就是處於執行期的程序(當然包括系統資源),實際上正在執行的程序代碼的活標本。那麼進程的邏輯地址空間是如何劃分的呢?

圖1做了簡單的說明(Linux系統下的):

圖一

左邊的是UNIX/LINUX系統的執行文件,右邊是對應進程邏輯地址空間的劃分情況。

一般認為在c中分為這幾個存儲區: 1. 棧 --有編譯器自動分配釋放 2. 堆 -- 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收 3. 全局區(靜態區) -- 全局變數和靜態變數的存儲是放在一塊的,初始化的全局變數和靜態變數在一塊區域,未初始化的全局變數和未初始化的靜態變數在相鄰的另一塊區域。程序結束釋放。 4. 另外還有一個專門放常量的地方。程序結束釋放。 在函數體中定義的變數通常是在棧上,用malloc, calloc, realloc等分配內存的函數分配得到的就是在堆上。在所有函數體外定義的是全局量,加了static修飾符後不管在哪裡都存放在全局區(靜態區),在所有函數體外定義的static變數表示在該文件中有效,不能extern到別的文件用,在函數體內定義的static表示只在該函數體內有效。另外,函數中的"adgfdf"這樣的字元串存放在常量區。比如:代碼:

int a = 0; //全局初始化區

char *p1; //全局未初始化區

main(){

int b; //棧

char s[] = "abc"; //棧

char *p2; //棧

char *p3 = "123456"; //123456在常量區,p3在棧上。

static int c = 0; //全局(靜態)初始化區

p1 = (char *)malloc(10);

p2 = (char *)malloc(20);//分配得來得10和20位元組的區域就在堆區。

strcpy(p1, "123456");//123456放在常量區,編譯器可能會將它與p3所指向 的"123456"優化成一塊。

}

還有就是函數調用時會在棧上有一系列的保留現場及傳遞參數的操作。 棧的空間大小有限定,vc的預設是2M。棧不夠用的情況一般是程序中分配了大量數組和遞歸函數層次太深。有一點必須知道,當一個函數調用完返回後它會釋放該函數中所有的棧空間。棧是由編譯器自動管理的,不用你操心。 堆是動態分配內存的,並且你可以分配使用很大的內存。但是用不好會產生內存泄漏。並且頻繁地malloc和free會產生內存碎片(有點類似磁碟碎片),因為c分配動態內存時是尋找匹配的內存的。而用棧則不會產生碎片。 在棧上存取數據比通過指針在堆上存取數據快些。 一般大家說的堆棧和棧是一樣的,就是棧(stack),而說堆時才是堆heap. 棧是先入後出的,一般是由高地址向低地址生長。

堆(heap)和堆棧(stack)的區別

2.1申請方式stack:由系統自動分配。 例如,聲明在函數中一個局部變數 int b; 系統自動在棧中為b開辟空間heap:需要程序員自己申請,並指明大小,在c中malloc函數

如p1 = (char *)malloc(10);

在C++中用new運算符

如p2 = (char *)malloc(10);

但是注意p1、p2本身是在棧中的。

2.2 申請後系統的響應棧:只要棧的剩餘空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。堆:首先應該知道操作系統有一個記錄空閑內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閑結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閑鏈表中。

2.3

2.4申請效率的比較:棧由系統自動分配,速度較快。但程序員是無法控制的。堆是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,他不是在堆,也不是在棧是直接在進程的地址空間中保留一快內存,雖然用起來最不方便。但是速度快,也最靈活。

2.5堆和棧中的存儲內容棧: 在函數調用時,第一個進棧的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然後是函數中的局部變數。注意靜態變數是不入棧的。當本次函數調用結束後,局部變數先出棧,然後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。堆:一般是在堆的頭部用一個位元組存放堆的大小。堆中的具體內容有程序員安排。

2.6存取效率的比較

char s1[] = "aaaaaaaaaaaaaaa";

char *s2 = "bbbbbbbbbbbbbbbbb";

aaaaaaaaaaa是在運行時刻賦值的;

而bbbbbbbbbbb是在編譯時就確定的;

但是,在以後的存取中,在棧上的數組比指針所指向的字元串(例如堆)快。

比如:#include <...>

void main(){

char a = 1;

char c[] = "1234567890";

char *p ="1234567890";

a = c[1];

a = p[1];

return;

}

對應的匯編代碼

10: a = c[1];

00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]

0040106A 88 4D FC mov byte ptr [ebp-4],cl

11: a = p[1];

0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]

00401070 8A 42 01 mov al,byte ptr [edx+1]

00401073 88 45 FC mov byte ptr [ebp-4],al

第一種在讀取時直接就把字元串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,在根據edx讀取字元,顯然慢了。

2.7小結:堆和棧的區別可以用如下的比喻來看出:使用棧就象我們去飯館里吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等准備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。使用堆就象是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大。堆和棧的區別主要分:操作系統方面的堆和棧,如上面說的那些,不多說了。還有就是數據結構方面的堆和棧,這些都是不同的概念。這里的堆實際上指的就是(滿足堆性質的)優先隊列的一種數據結構,第1個元素有最高的優先權;棧實際上就是滿足先進後出的性質的數學或數據結構。雖然堆棧,堆棧的說法是連起來叫,但是他們還是有很大區別的,連著叫只是由於歷史的原因。

申請大小的限制棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。一、預備知識—程序的內存分配一個由c/C++編譯的程序佔用的內存分為以下幾個部分

1、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變數的值等。其操作方式類似於數據結構中的棧。2、堆區(heap)— 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表,呵呵。3、全局區(靜態區)(static)—全局變數和靜態變數的存儲是放在一塊的,初始化的全局變數和靜態變數在一塊區域, 未初始化的全局變數和未初始化的靜態變數在相鄰的另一塊區域。 - 程序結束後有系統釋放4、文字常量區 —常量字元串就是放在這里的。 程序結束後由系統釋放5、程序代碼區(text)—存放函數體的二進制代碼。

3. 定義結構體類型,說明了該類結構體數據的組織形式,在編譯程序時系統會給結構體類型分配空間。 為什麼

結構體類型是一種類型就和整型一樣,你沒有創建變數,舉個例子
int;這是一種類型這個不佔
int a;這是一個變數占內存
就和你說男的一樣,你只是說了男的,你沒有指明是誰呀
所以,只不過這個類型是你自己定義,

4. 全局變數系統將怎樣初始化,何時分配內存空間

2.1 內存分配策略
按照編譯原理的觀點,程序運行時的內存分配有三種策略,分別是靜態的,棧式的,和堆式的.
靜態存儲分配是指在編譯時就能確定每個數據目標在運行時刻的存儲空間需求,因而在編譯時就可以給他們分配固定的內存空間.這種分配策略要求程序代碼中不允許有可變數據結構(比如可變數組)的存在,也不允許有嵌套或者遞歸的結構出現,因為它們都會導致編譯程序無法計算準確的存儲空間需求.
棧式存儲分配也可稱為動態存儲分配,是由一個類似於堆棧的春改運行棧來實現的.和靜態存儲分配相反,在棧式存儲方案中,程序對數據區的需求在編譯時是完全未知的,只有到運行的時候才能夠知道,但是規定在運行中進入一個程序模塊時,必須知道該程序模塊所需的數據區大小才能夠為其分配內存.和我們在數據結構所熟知的棧一樣,棧式存儲分配按照先進後出的原則進行分配。
靜態存儲分配要求在編譯時能知道所有變數的存儲要求,棧式存儲分配要求在過程的入口處必須知道所有的存儲要求,而堆式存儲分配則專門負責在編譯時或運行時模塊入口處都無法確定存儲要求的數據結構的內存分配,比如可變長度串和對象實例.堆由大片的可利用塊或空閑塊組成,堆中的內存可以按照任意順序分配和釋放.
2.2 堆和棧的比較
上面的定義從編譯原理的教材中總結而來,除靜態存儲分配之外,都顯得很呆板和難以理解,下面撇開靜態存儲分配,集中比較堆和棧:
從堆和棧的功能和作用來通俗的比較,堆主要用來存放對象的,棧主要是用來執行程序的.而這種不同又主要是由於堆和棧的特點決定的:
編程中,例如C/C++中,所有的方法調用都是通過棧來進行的,所有的局部變數,形式參數都是從棧中分配內存空間的。實際上也不是什麼分配,只是從棧頂向上用就行,就好像工廠中的傳送帶(conveyor belt)一樣,Stack Pointer會自動指引你到放東西的位置,你所要做的只是把東西放下來就行.退出函數的時候,修改棧指針就可以把棧中源森好的內容銷毀.這樣的模式速度最快, 當然要用來運行程序了.需要注意的是,在分配的時候,比如為一個即將要調用的程序模塊分配數據區時,應事先知道這個數據區的大小,也就說是雖然分配是在程序運行時進行的,但是分配的大小多少是確定的,不變的,而這個"大小多少"是在編譯時確定的,不是在運行時.
堆是應用程序在運行的時候請求操作系統分配給自己內存,由於從操作系統管理的內存分配,所以在分配和銷毀時都要佔用時間,因此用堆的效率非常低.但是堆的優點在於,編譯器不必知道要從堆里分配多少存儲空間,也不必知道存儲的數據要在堆里停留多長的時間,因此,用堆保存數據時會得到更大的靈活性。事實上,面向對象的多態性,堆內存分配是必不可少的,因為多態變數所需的存儲空間只有在運行時創建了對象之後才能確定.在C++中,要求創建一個對象時,只需用 new命令編制相關的代碼即可。執行這些代碼時,會在堆里自動進行數據的保存.當然,為達到這種靈活性,必然會付出一定的代價:在堆里分配存儲空間時會花掉更長的時間!這也正是導致我們剛才所說的效率低的原因,看來列寧同志說的好,人的優點往往也是人的缺點,人的缺點往往也是人的優點(暈~).

2.3 JVM中的堆和棧
JVM是基於堆棧的虛擬機.JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。
我們知道,某個線程正在執行的方法稱為此線程的當前方法.我們可能不知道,當前方法使用的幀稱為當前幀。當線程激活一個Java方法,JVM就會在線程的 Java堆棧里新壓入一個幀。這個幀自然成為了當前幀.在此方法執行期間,這個幀將用來保存參數,局雹鉛部變數,中間計算過程和其他數據.這個幀在這里和編譯 原理中的活動紀錄的概念是差不多的.
從Java的這種分配機制來看,堆棧又可以這樣理解:堆棧(Stack)是操作系統在建立某個進程時或者線程(在支持多線程的操作系統中是線程)為這個線程建立的存儲區域,該區域具有先進後出的特性。
每一個Java應用都唯一對應一個JVM實例,每一個實例唯一對應一個堆。應用程序在運行中所創建的所有類實例或數組都放在這個堆中,並由應用所有的線程 共享.跟C/C++不同,Java中分配堆內存是自動初始化的。Java中所有對象的存儲空間都是在堆中分配的,但是這個對象的引用卻是在堆棧中分配,也 就是說在建立一個對象時從兩個地方都分配內存,在堆中分配的內存實際建立這個對象,而在堆棧中分配的內存只是一個指向這個堆對象的指針(引用)而已。
具體的說:

5. 【求助】C#編譯器怎麼為類分配內存空間

不會C++,所以不太理解LZ的意思。
那個,C++里的new 是在編譯時確定要分配的內存大小嗎?
比如在編譯A a=new A ();這一句時,編譯器就需要計算A的大小,並預留出內存空間?
(上面是我根據LZ的描述猜的)

在託管環境中,類型的載入(從程序集里載入)、實例化、回收 都是由CLR(公共語言運行時)在運行時執行的。
所以在編譯A a=new A ();時,編譯器不需要知道該為A分配多大的空間,只是簡單的記錄一下要創建一個新的A對象。這個創建操作是當你執行Test方法時由CLR來執行的。

6. 關於C語言動態分配內存的問題

要實現動態內存的分配,除了利用含指針成員的結構體之外,還需利用C語言提供的幾個標准庫函數。(使用時應包含頭文件「alloc.h」或「malloc.h」或「stdlib.h」)
1.malloc函數
函數原型為void *malloc(unsigned int size);在內存的動態存儲區中分配一塊長度為"size" 位元組的連續區域。函數的返回值為該區域的首地址。 「類型說明符」表示把該區域用於何種數據類型。(類型說明符*)表示把返回值強制轉換為該類型指針。「size」是一個無符號數。例如: pc=(char *) malloc (100); 表示分配100個位元組的內存空間,並強制轉換為字元數組類型,函數的返回值為指向該字元數組的指針, 把該指針賦予指針變數pc。若size超出可用空間,則返回空指針值NULL。
2.calloc 函數
函數原型為void *calloc(unsigned int num, unsigned int size)
按所給數據個數和每個數據所佔位元組數開辟存儲空間。其中num為數據個數,size為每個數據所佔位元組數,故開辟的總位元組數為 num*size。函數返回該存儲區的起始地址。calloc函數與malloc 函數的區別僅在於一次可以分配n塊區域。例如: ps=(struct stu*) calloc(2,sizeof (struct stu)); 其中的sizeof(struct stu)是求stu的結構長度。因此該語句的意思是:按stu的長度分配2塊連續區域,強制轉換為stu類型,並把其首地址賦予指針變數ps。
3. realloc函數:
函數原型為void *realloc(void *ptr, unsigned int size)
重新定義所開辟內存空間的大小。其中ptr所指的內存空間是用前述函數已開辟的,size為新的空間大小,其值可比原來大或小。函數返回新存儲區的起始地 址(該地址可能與以前的地址不同)。例如p1=(float *)realloc(p1,16);將原先開辟的8個位元組調整為16個位元組。
**動態申請的內存空間要進行手動用free()函數釋放

例子:

char *p;
p=(char*)malloc(8);//開辟8個位元組的存儲空間,並把地址賦給指針p,通過指針p對該空間進行存取操作。
*p='L'; //存儲字元,所分配空間的第0位元組存儲L
*(p+1)='o';//分配空間的第一位元組存儲字元'o'.
*(p+2)='v';
*(p+3)='e';
*(p+4)='\0';
puts(p);//輸出字元串
free(p);//釋放空間
注意:*(p+n)等價於p[n],(p+n)是地址,而*(p+n)就是取地址(p+n)的內容。
如上面程序中的*(p+1)='A';可寫成p[1]='A';
malloc()函數的參數可以是常數、變數或表達式等。除了存放字元串外,malloc()也可取納判得空間來存儲整數等數橘茄悉據。例如存儲整數分配空間如下:
圓乎int *ptr;
ptr=(int *)malloc(sizeof(int)*4);
malloc()開辟空間存儲4個整數數據,由於malloc()總傳回第0位元組的地址,且返回值必定是char*類型,所以要通過(int *)來強制轉換為指向整型後存入指向整型的指針ptr.
當用malloc()函數分配空間時,若計算機無法提供足夠的空間分配則會返回NULL指針。所以,若返回的指針為NULL,就表示可分配的剩餘空間已不足。

7. 操作系統裝載程序的時候,為程序都分配了那幾塊空間,每塊空間的大小如何確定

一般分兩大塊,一塊是主分區,一塊是邏輯分咐猜型區。一般情況下只有C盤是主分區,其他都是邏輯分區,不過部分筆記本的還原盤也是隱藏的主分區。至於空間的衡猜大小很好確定啊,打開我的電腦看看每個分區兆歷的容量就知道了

8. c語言中編譯系統和操作系統誰為變數分配相應的存儲空間

編譯系統將程序編譯成可執行代碼

操作系統執行程序,按照可執行代碼需求為程序分配代碼空間、常量空間、變數空間、堆棧空間,然後執行程序。

9. 全局變數在編譯時怎麼分配空間

關於這個問題,全局變數(成員變數)是在創建對象的時候分配內存的創建對象過程為1分配空間2遞歸的創建父類對象(無父類這步可省略)3初始化成員變數4調用構造方法創建一個對象
靜態變數是在類載入的時候分配空間的,靜態變數和對象沒有關系是在jvm第一次讀到一個類的時候載入信息的過程中分配空間的類載入過程為1載入父類(如果父類已經載入過,則不在載入)2初始化靜態屬性3按順序的初始化靜態代碼塊
初始化的前提就是分配空間
而且靜態變數在以後的創建對象的時候不在初始化所以一般用靜態來保存共享信息
希望對你有所幫助

10. C++程序運行時的內存空間如何分區

C++程序的內純格局通常分為4個區:
1.數據區(Data Area)
2.代碼區(Code Area)
3.棧區(Stack Area)
4.堆區(即自由存儲區)(Heap Area)
全局變數、靜態變數、常量存放在數據區,所有類成員函數和非成員函數代碼存放在代碼區,為運行函數而分配的局部變數、函數參數、返回數據、返回地址等存放在棧區,餘下的空間為堆區。

因為堆是有限的,它可能變得擁擠,如果堆中沒有足夠的自由空間以滿足內存的需要時,那麼此需要失敗,並穗碧激且返回一個空猜襪指針。因此,必須在使用NEW生成的指針之前進行檢查,方法如下:
C++代碼
HeapClass *pa1 , *pa2;
pa1 = new HeapClass(4); // 分配空間
pa2 = new HeapClass (); // 分配空間
if(!pa1 || !pa2){ // 檢查空間
cout<<"out of Memory"<<endl;
return;
}

HeapClass *pa1 , *pa2;
pa1 = new HeapClass(4); // 分配空間
pa2 = new HeapClass (); // 分配空間
if(!pa1 || !pa2){ // 檢查空間
cout<<"out of Memory"<<endl;
return;
}

一般來說,堆空間相對其他內存空間比慧正較空閑,隨要隨拿,給程序運行帶來了較大的自由度,但是管理堆區是一件十分復雜的工作,頻繁地分配(NEW)和釋放(DELETE)不同大小的堆空間將會產生堆內碎塊。使用堆空間往往由於:
.直到運行時才能知道需要多少對象空間;
.不知道對象的生存期到底有多長;
.直到運行時才知道一個對象需要多少內存空間;

閱讀全文

與編譯器如何請求操作系統分配空間相關的資料

熱點內容
下班之後的程序員 瀏覽:69
檢測支持ssl加密演算法 瀏覽:340
衢州發布新聞什麼APP 瀏覽:82
中國移動長沙dns伺服器地址 瀏覽:249
wifi密碼加密了怎麼破解嗎 瀏覽:596
linux命令cpu使用率 瀏覽:67
linux實用命令 瀏覽:238
傳奇引擎修改在線時間命令 瀏覽:109
php取域名中間 瀏覽:897
cad命令欄太小 瀏覽:830
php開發環境搭建eclipse 瀏覽:480
qt文件夾名稱大全 瀏覽:212
金山雲伺服器架構 瀏覽:230
安卓系統筆記本怎麼切換系統 瀏覽:618
u盤加密快2個小時還沒有搞完 瀏覽:93
小米有品商家版app叫什麼 瀏覽:94
行命令調用 瀏覽:436
菜鳥裹裹員用什麼app 瀏覽:273
窮查理寶典pdf下載 瀏覽:515
csgo您已被禁用此伺服器怎麼辦 瀏覽:398