2009年4月24日 星期五

C++ 變數的存放位置跟static三個用法

今天上課聽了一些關於變數的存放
以前寫程式時都不會注意這些東西,就姑且把他記下來了



首先看上面這張圖,一個Procress在Runtime期間,都會配置像這樣一塊記憶體規畫
他被分成四大塊:stack、heap、.data、.text,.data也可以再分成(.bss,.data)
然後只有stack跟heap是變動的,其他都是compile時候就固定了

stack


non-static的location variable(區域變數)都放會這邊,他是隨著function call一層一層堆疊,因此每進入一個scope就會疊一層,每離開一個scope就會少一層。
這邊特別標註non-static,因為static變數的話其生命週期(lifetime)會改變,雖然他仍是區域變數,但是他會放到.data的地方。

void f(){
int i;\\nont-static location variable in stack
static int l;\\static location variable in .data
}


heap


這塊區域的記憶體是由user來決定其增減的,他主要存放所有"new"出來的dynamic variable,也就是在runtime期間請求的記憶體,直得一提的是,java所有object都放在heap裡面,這是為了可以讓GC實現。
因為new出來的東西是user請求,他主要回傳一個指標(Pointer),所以相關回收動作也要由user去做,因為系統不會幫user回收new出來的記憶體。
系統只會去回收stack上的memory,如果不回收這些new出來的記憶體,而又用不到他就會造成memory leak,所以new出來的東西要由user自己去delete。
在此特別提一下,通常delete之後會再讓該指標指向NULL(第0塊位置),這是為了讓系統可以去回收這塊記憶體。就算記憶體被free掉,指標仍可以指向他。

new跟delete兩大步驟


new

  1. Memory allocation:先向heap去規劃一塊記憶體

  2. Initialization:初始化,呼叫物件建構子初始那塊記憶體


delete

  1. clean up:呼叫解構子清空那塊記憶體

  2. free:歸還塊記憶體



其中,那些步驟是可以單獨出現的,譬如說只呼叫解構子而沒有歸還記憶體,所以delete之後還要讓指標指向NULL

.data


這塊區域主要存放Global跟static variable,為了讓lifetime不受scope影響的物件可以被任何地方存取,這塊記憶體會固定且一開始就規劃好。

.text


主要是放程式碼的地方


這邊再舉個有趣的例子

void f(){
int* pa=new int;
}


在這裡要分成兩方面來看,pa是由我們宣告出來的"區域變數",注意!他仍是location variable
但是奇怪,上面不是說new出來的東西會放在heap。
沒錯我new出來的是放在heap,但是我new的是int而不是pa阿,pa仍是一個區域變數,只是他會指到heap去。

就是這樣,只有new出來的東西會放在heap,他通常是我們指標指向的實體,所以new出來後不去delete就會有一塊垃圾產生在那裏


static三個用處


static根據在不同的地方會有不同的解釋

在localation時使用:更改變數lifetime

用在區域變數時,他可以改變區域變數的生命週期,讓他不會出了scope即被回收,也就是他不會被放在stack而是放在.data裡面

void f(){
int i;\\nont-static location variable in stack
static int l;\\static location variable in .data
}


在Global時使用:更改變數scope

當他用在全域變數宣告時,他會從global scope變成file scope,也就是只有這個"檔案"可以使用他,其他link的目標檔則無法使用

舉個例子


//Test1.cpp
static int a;
int b;
void main(){
}


Test2.cpp
static int a;
static int c;
void main(){
}


在編譯程可執行檔的時候,會將所需程式或lib變成目標檔(.o)再透過連結器(linker)將他們link起來,才會變成我平常所需的可執行檔,在這邊所說file scope就是指一個.o檔
如上面例子,只有b是全域變數,Test1還是Test2都可以使用這個變數,但是a、c都被static變成了file scope,只有自己檔案看的到,所以不用有變數名稱重複的問題,因為scope不同,Test1看不到也不能用Test2的a,同樣的Test2的a也跟Test1的a不相干。

在Class時使用:讓member是Perclass


當在class的member使用static修飾子的時候代表,這個member是全部的instance都可以share的,大家共用一份,同時class不需要產生instance就可以使用

沒有留言: