內存的靜態分配和動態分配的區別

內存的靜態分配和動態分配的區別主要是兩個:

      一是時間不同。靜態分配發生在程序編譯和連接的時候。動態分配則發生在程序調入和執行的時候。

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

對於一個進程的內存空間而言,可以在邏輯上分成3個部份:代碼區,靜態數據區和動態數據區。動態數據區一般就是“堆棧”。“棧(stack)”和“堆(heap)”是兩種不同的動態數據區,棧是一種線性結構,堆是一種鏈式結構。進程的每個線程都有私有的“棧”,所以每個線程雖然代碼一樣,但本地變量的數據都是互不干擾。一個堆棧可以通過“基地址”和“棧頂”地址來描述。全局變量和靜態變量分配在靜態數據區本地變量分配在動態數據區,即堆棧中。程序通過堆棧的基地址和偏移量來訪問本地變量。

 

一般,用static修飾的變量,全局變量位於靜態數據區。函數調用過程中的參數,返回地址,EBP和局部變量都採用棧的方式存放。

 

 

所謂動態內存分配就是指在程序執行的過程中動態地分配或者回收存儲空間的分配內存的方法。動態內存分配不象數組等靜態內存分配方法那樣需要預先分配存儲空間,而是由系統根據程序的需要即時分配,且分配的大小就是程序要求的大小。
例如我們定義一個float型數組:float score[100];   
但是,在使用數組的時候,總有一個問題困擾着我們:數組應該有多大?在很多的情況下,你並不能確定要使用多大的數組,比如上例,你可能並不知道我們要定義的這個數組到底有多大,那麼你就要把數組定義得足夠大。這樣,你的程序在運行時就申請了固定大小的你認爲足夠大的內存空間。即使你知道你想利用的空間大小,但是如果因爲某種特殊原因空間利用的大小有增加或者減少,你又必須重新去修改程序,擴大數組的存儲範圍。這種分配固定大小的內存分配方法稱之爲靜態內存分配。但是這種內存分配的方法存在比較嚴重的缺陷,特別是處理某些問題時:在大多數情況下會浪費大量的內存空間,在少數情況下,當你定義的數組不夠大時,可能引起下標越界錯誤,甚至導致嚴重後果。 
我們用動態內存分配就可以解決上面的問題. 所謂動態內存分配就是指在程序執行的過程中動態地分配或者回收存儲空間的分配內存的方法。動態內存分配不象數組等靜態內存分配方法那樣需要預先分配存儲空間,而是由系統根據程序的需要即時分配,且分配的大小就是程序要求的大小。從以上動、靜態內存分配比較可以知道動態內存分配相對於景泰內存分配的特點: 
   1、不需要預先分配存儲空間;
   2、分配的空間可以根據程序的需要擴大或縮小。 
要實現根據程序的需要動態分配存儲空間,就必須用到malloc函數.
malloc函數的原型爲:void *malloc (unsigned int size) 其作用是在內存的動態存儲區中分配一個長度爲size的連續空間。其參數是一個無符號整形數,返回值是一個指向所分配的連續存儲域的起始地址的指針。還有一點必須注意的是,當函數未能成功分配存儲空間(如內存不足)就會返回一個NULL指針。所以在調用該函數時應該檢測返回值是否爲NULL並執行相應的操作。
靜態內存是在程序一開始運行就會分配內存,直到程序結束了,內存才被釋放。
動態內存是在程序調用在程序中定義的函數時才被分配,函數調用結束了,動態內存就釋放。
static int a;這是定義了一個靜態的變量
int a;這是定義了一個動態的變量;
靜態內存可以用於求階層。
例如:
jiechen(int i)
{static int a=1;
for(;a<=i,a++)
return a*i;
}
#include"stdio.h"
main()
{int a,i;
printf("enter number:")
scanf("%d",&a);
for(i=1;i<=a;i++)
printf("i!=%d\n",jiechen(i));

}
運行
輸入3
結果爲1!=1
      2!=2
      3!=3
 
 
由malloc系統函數分配的內存就是從堆上分配內存。從堆上分配的內存一定要自己釋放。用free釋放,不然就是術語——“內存泄露”(或是“內存漏洞”)—— Memory Leak。於是,系統的可分配內存會隨malloc越來越少,直到系統崩潰。還是來看看“棧內存”和“堆內存”的差別吧。

    棧內存分配
    —————
    char*
    AllocStrFromStack()
    {
        char pstr[100];
        return pstr;
    }
   
    堆內存分配
    —————
    char*
    AllocStrFromHeap(int len)
    {
        char *pstr;
        
        if ( len <= 0 ) return NULL;
        return ( char* ) malloc( len );
    }

對於第一個函數,那塊pstr的內存在函數返回時就被系統釋放了。於是所返回的char*什麼也沒有。而對於第二個函數,是從堆上分配內存,所以哪怕是程序退出時,也不釋放,所以第二個函數的返回的內存沒有問題,可以被使用。但一定要調用free釋放,不然就是Memory Leak!

在堆上分配內存很容易造成內存泄漏,這是C/C++的最大的“剋星”,如果你的程序要穩定,那麼就不要出現Memory Leak。所以,我還是要在這裏千叮嚀萬囑付,在使用malloc系統函數(包括calloc,realloc)時千萬要小心。

記得有一個UNIX上的服務應用程序,大約有幾百的C文件編譯而成,運行測試良好,等使用時,每隔三個月系統就是down一次,搞得許多人焦頭爛額,查不出問題所在。只好,每隔兩個月人工手動重啓系統一次。出現這種問題就是Memery Leak在做怪了,在C/C++中這種問題總是會發生,所以你一定要小心。一個Rational的檢測工作——Purify,可以幫你測試你的程序有沒有內存泄漏。

我保證,做過許多C/C++的工程的程序員,都會對malloc或是new有些感冒。當你什麼時候在使用malloc和new時,有一種輕度的緊張和惶恐的感覺時,你就具備了這方面的修養了。
對於malloc和free的操作有以下規則:

1) 配對使用,有一個malloc,就應該有一個free。(C++中對應爲new和delete)
2) 儘量在同一層上使用,不要像上面那種,malloc在函數中,而free在函數外。最好在同一調用層上使用這兩個函數。
3) malloc分配的內存一定要初始化。free後的指針一定要設置爲NULL。    

注:雖然現在的操作系統(如:UNIX和Win2k/NT)都有進程內存跟蹤機制,也就是如果你有沒有釋放的內存,操作系統會幫你釋放。但操作系統依然不會釋放你程序中所有產生了Memory Leak的內存,所以,最好還是你自己來做這個工作。(有的時候不知不覺就出現Memory Leak了,而且在幾百萬行的代碼中找無異於海底撈針,Rational有一個工具叫Purify,可能很好的幫你檢查程序中的Memory Leak)
 
第一個例子也講得不清楚。所謂系統釋放,應該是指系統在自己的表裏把這段內存標記爲可以使用,以後可以被別的程序使用,所以第一個例子會造成程序能訪問到已經釋放的內存空間,是越界,會造成不可預測的情況。
系統一般不會自動去清除釋放空間內的數據,而是由以後的程序來覆蓋。所以很多程序開頭都會做MEMSET(...),就是爲了防止這種垃圾數據的情況。

如果在程序運行中要改變內存塊的大小,可以用RALLOC()函數,它能在原來地址上重新分配一塊空間,不過是用的時候要小心,也是比較容易出問題



來源:http://blog.csdn.net/liuchao1986105/article/details/6724392

參考:http://blog.csdn.net/masefee/article/details/6835688

發佈了17 篇原創文章 · 獲贊 33 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章