国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - 關于C語言程序的內存分配的入門知識學習

關于C語言程序的內存分配的入門知識學習

2021-03-17 15:03C語言教程網 C/C++

這篇文章主要介紹了關于C語言程序的內存分配的入門知識學習,特別強調了堆與棧的內存空間申請比較,需要的朋友可以參考下

C語言程序的存儲區域

C語言編寫的程序經過編繹-鏈接后,將形成一個統一的文件,它由幾個部分組成,在程序運行時又會產生幾個其他部分,各個部分代表了不同的存儲區域:

代碼段(Code or Text):代碼段由程序中的機器碼組成。在C語言中,程序語句進行編譯后,形成機器代碼。在執行程序的過程中,CPU的程序計數器指向代碼段的每一條代碼,并由處理器依次運行。
只讀數據段(RO data):只讀數據段是程序使用的一些不會被更改的數據,使用這些數方式類似查表式的操作,由于這些變量不需要更改,因此只需要放置在只讀存儲器中即可。
已初始化讀寫數據段(RW data):已初始化數據是在程序中聲明,并且具有初值的變量,這些變量需要占用存儲器的空間,在程序執行時它們需要位于可讀寫的內存區域內,并具有初值,以供程序運行時讀寫。
未初始化讀寫數據段(BSS):未初始化讀寫據是在程序中聲明,但是沒有初始化的變量,這些變量在程序運行之前不需要占用存儲器的空間。
堆(heap):堆內存只在程序運行時出現,一般由程序員分配和釋放。在具有操作系統的情況下,如果程序員沒釋放,操作系統可以在程序結束后回收內存。
棧(stack):棧內存只在程序運行時出現,在函數內部使用的變量,函數的參數以及返回值將使用棧空間,棧空間由編譯器自動分配和釋放。
C語言目標文件的內存布局如圖:

關于C語言程序的內存分配的入門知識學習

代碼段,只讀數據段,讀寫數據段,未初始化數據段屬于靜態區域,而堆和棧屬于動態區域。代碼段,只讀數據段和讀寫數據段將在連接之后產生,未初始化數據段將在程序初始化的時候開辟,而堆和棧將在程序的運行中分配和釋放。

C語言程序分為映像和運行時兩種狀態,在編譯連接后形成的映像中,將只包含代碼段,只讀數據段和讀寫數據段,在程序運行之前,將動態生成未初始化數據段,在程序運行時還將動態形成堆區域和棧區域。

一般來說,在靜態的映像文件中,各個部分稱之為節(Section),而在運行時的各個部分稱之為段(Segment),有時統稱為段。

C語言程序的段

代碼段(code):代碼段由各個函數產生,函數的每一個語句將最終經過編繹和匯編生成二進制機器代碼(具體生生哪種體系結構的機器代碼由編譯器決定)。
只讀數據段(RO Data):只讀數據段由程序中所使用的數據產生,該部分數據的特點是在運行中不需要改變,因此編譯器會將該數據段放入只讀的部分中。C語言中的只讀全局變量,只讀局部變量,程序中使用的常量等會在編譯時被放入到只讀數據區。注意:定義全局變量const char a[100]={"ABCDEFG"};將生成大小為100個字節的只讀數據區,并使用“ABCDEFG”初始化。如果定義為:const char a[ ]={"ABCDEFG"};則根據字符串長度生成8個字節的只讀數據段(還有'\0'),所以在只讀數據段中,一般都需要做完全的初始化。
讀寫數據段(RW Data):讀寫數據段表示了在目標文件中一部分可以讀也可以寫的數據區,在某些場合它們又被稱為已初始化數據段,這部分數據段和代碼段,與只讀數據段一樣都屬于程序中的靜態區域,但具有可寫性的特點。通常已初始化的全局變量和局部靜態變量被放在了讀寫數據段,如: 在函數中定義static char b[ 100]={“ABCDEFG”};讀寫數據區的特點是必須在程序經過初始化,如果只定義,沒初始值,則不會生成讀寫數據區,而會定位為未初始化數據區(BSS)。如果全局變量(函數外部定義的變量)加入static修飾,這表示只能在文件內使用,而不能被其他文件使用。
未初始化數據段(BSS):與讀寫數據段類似,它也屬于靜態數據區,但是該段中的數據沒有經過初始化。因此它只會在目標文件中被標識,而不會真正稱為目標文件中的一段,該段將會在運行時產生。未初始化數據段只在運行的初始化階段才會產生,因此它的大小不會影響目標文件的大小。
在C語言的程序中,對變量的使用還有以下幾點需要注意:

函數體中定義的變量通常是在棧上,不需要在程序中進行管理,由編繹器處理。
用malloc,calloc,realloc等分配內存的函數所分配的內存空間在堆上,程序必須保證在使用free釋放,否則會發生內存泄漏。
所有函數體外定義的是全局變量,加了static后的變量不管是在函數內部或外部都放在全局區。
使用const定義的變量將放于程序的只讀數據區。

程序中段的使用

下面用一個簡單的例子來說明C語言中變量和段的對應關系。C語言程序中的全局區(靜態區),實際對應著下述幾個段:RO Data; RW Data ; BSS Data.一般來說,直接定義的全局變量在未初始化數據區,如果該變量有初始化則是在已初始化數據區(RW Data),加上const則將放在只讀數據區。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const char ro[ ] = {"this is read only data"};  //只讀數據區
static char rw_1[ ] ={"this is global read write data"}; //已初始化讀寫數據段
char BSS_1[ 100];                //未初始化數據段
const char *ptrconst ="constant data";      //字符串放在只讀取數據段
int main()
{
    short b;                 //在棧上,占用2個字節
    char a[100];               //在棧上開辟100個字節,工的值是其首地址
    char s[ ]="abcdefg";           //s在棧上,占用4個字節
                         //"abcdefg"本身放置在只讀數據存儲區,占8個字節
 
    char *p1;                 //p1在棧上,占用4個字節      
    char *p2="123456";            //p2 在棧上,p2指向的內容不能改,
                         //“123456”在只讀數據區
 
    static char rw_2[ ]={"this is local read write data"};//局部已初始化讀寫數據段
    static char BSS_2[100];          //局部未初始化數據段
    static int c = 0;             //全局(靜態)初始化區
    p1=(char *)malloc(10 * sizeof(char ) );  //分配內存區域在堆區
    strcpy(p1,"xxxx");            //“XXXX”放在只讀數據區,占5個字節
    free(p1);                 //使用free釋放p1所指向的內存
    return 0;
}

讀寫數據段包含了憶初始化的全局變量 static char rw_1[ ]以及局部靜態變量static rw_2[ ].其差別在于編繹時,是在函人部使用的還是可以在整個文件中使用。對于rw_1[] 無論有無static 修飾,其都將被放置在讀寫數據區,只是能否被其它文件引用與否。對于后者就不一樣了,它是局部靜態變量,放置在讀寫數據區,如果沒static修飾,其意義完全改變,它將會是開辟在棧空間的局部變量,而不是靜態變量,在這里rw_1[],rw_2[]后沒具體數值,表示靜態區大小同后面字符串長度決定。

對于未初始化數據區BSS_1[100]與BSS_2[100],其區別在于前者是全局變量,在所有文件中都可以使用;后者是局部變量,只在函數內部使用。未初始化數據段不設置后面的初始化數值,因此必須使用數值指定區域的大小,編繹器將根據大小設置BSS中需要增加的長度。

棧空間主要用于以下3數據的存儲:

  1. 函數內部的動態變量
  2. 函數的參數
  3. 函數的返回值

棧空間是動態開辟與回收的。在函數調用過程中,如果函數調用的層次比較多,所需要的棧空間也逐漸加大,對于參數的傳遞和返回值,如果使用較大的結構體,在使用的棧空間也會比較大。

堆與棧的比較

1.申請方式

  stack: 由系統自動分配。 例如,聲明在函數中一個局部變量 int b; 系統自動在棧中為b開辟空間。

  heap: 需要程序員自己申請,并指明大小,在C中malloc函數,C++中是new運算符。

  如

?
1
p1 = (char *)malloc(10); p1 = new char[10];

  如

?
1
p2 = (char *)malloc(10); p2 = new char[20];

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

2.申請后系統的響應

  棧:只要棧的剩余空間大于所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。

  堆:首先應該知道操作系統有一個記錄空閑內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆結點,然后將該結點從空閑結點鏈表中刪除,并將該結點的空間分配給程序。

  對于大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。

  由于找到的堆結點的大小不一定正好等于申請的大小,系統會自動的將多余的那部分重新放入空閑鏈表中。

3.申請大小的限制

  棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。

  堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由于系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。

4.申請效率的比較

  棧由系統自動分配,速度較快。但程序員是無法控制的。

  堆是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便。

  另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,他不是在堆,也不是棧,而是直接在進程的地址空間中保留一快內存,雖然用起來最不方便。但是速度快,也最靈活。

5.堆和棧中的存儲內容

  棧:在函數調用時,第一個進棧的是主函數中后的下一條指令(函數調用語句的下一條可執行語句)的地址,然后是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然后是函數中的局部變量。注意靜態變量是不入棧的。

  當本次函數調用結束后,局部變量先出棧,然后是參數,最后棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。

  堆:一般是在堆的頭部用一個字節存放堆的大小。堆中的具體內容有程序員安排。

6.存取效率的比較

?
1
2
3
char s1[] = "a";
 
char *s2 = "b";

  a是在運行時刻賦值的;而b是在編譯時就確定的;但是,在以后的存取中,在棧上的數組比指針所指向的字符串(例如堆)快。

  比如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main(){
 
char a = 1;
 
char c[] = "1234567890";
 
char *p ="1234567890";
 
a = c[1];
 
a = p[1];
 
return 0;
 
}

  對應的匯編代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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讀取字符,顯然慢了。

7.小結

  堆和棧的主要區別由以下幾點:

  (1)、管理方式不同;

  (2)、空間大小不同;

  (3)、能否產生碎片不同;

  (4)、生長方向不同;

  (5)、分配方式不同;

  (6)、分配效率不同;

  管理方式:對于棧來講,是由編譯器自動管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產生memory leak。

  空間大小:一般來講在32位系統下,堆內存可以達到4G的空間,從這個角度來看堆內存幾乎是沒有什么限制的。但是對于棧來講,一般都是有一定的空間大小的,例如,在VC6下面,默認的棧空間大小是1M。當然,這個值可以修改。

  碎片問題:對于堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進后出的隊列,他們是如此的一一對應,以至于永遠都不可能有一個內存塊從棧中間彈出,在他彈出之前,在他上面的后進的棧內容已經被彈出,詳細的可以參考數據結構。

  生長方向:對于堆來講,生長方向是向上的,也就是向著內存地址增加的方向;對于棧來講,它的生長方向是向下的,是向著內存地址減小的方向增長。

  分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配由mallo函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。

  分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很復雜的,例如為了分配一塊內存,庫函數會按照一定的算法(具體的算法可以參考數據結構/操作系統)在堆內存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內存碎片太多),就有可能調用系統功能去增加程序數據段的內存空間,這樣就有機會分到足夠大小的內存,然后進行返回。顯然,堆的效率比棧要低得多。

  從這里我們可以看到,堆和棧相比,由于大量new/delete的使用,容易造成大量的內存碎片;由于沒有專門的系統支持,效率很低;由于可能引發用戶態和核心態的切換,內存的申請,代價變得更加昂貴。所以棧在程序中是應用最廣泛的,就算是函數的調用也利用棧去完成,函數調用過程中的參數,返回地址, EBP和局部變量都采用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆。

  雖然棧有如此眾多的好處,但是由于和堆相比不是那么靈活,有時候分配大量的內存空間,還是用堆好一些。

  無論是堆還是棧,都要防止越界現象的發生(除非你是故意使其越界),因為越界的結果要么是程序崩潰,要么是摧毀程序的堆、棧結構,產生以想不到的結果。

延伸 · 閱讀

精彩推薦
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 亚洲 在线 | 欧美日韩国产一区二区三区 | 亚洲成人自拍 | 精品黄色一级片 | 日韩成人在线影院 | 国产成人高清 | 久久国产精品一区二区三区 | 精品久| 日本中文一区二区 | 中国黄色片在线观看 | 干片网 | 一区二区日韩精品 | 国产成人一区二区三区 | www中文字幕在线观看 | 久久网站热最新地址 | 日夜夜精品视频 | 成人午夜视频在线观看 | 亚洲午夜成激人情在线影院 | 日韩免费 | 欧美激情亚洲 | 久久亚洲一区 | 国产在线成人 | 久久亚洲国产 | 欧美国产另类 | 狠狠综合 | 久久久久一区二区 | 狠狠干美女 | 高清在线一区二区 | 在线观看一区二区三区四区 | 日比视频网站 | 日韩欧美一级片在线观看 | 亚洲福利精品 | 亚洲一区二区三区四区五区午夜 | 国产精品一区二区av | 人人干日日干 | 国产欧美日韩 | 日日嗨av一区二区三区四区 | 久久久99久久 | 这里只有精品在线 | 91精品国产乱码久久久久久久久 | 亚洲性人人天天夜夜摸 |