http://www.codeproject.com/Articles/76153/Six-important-NET-concepts-Stack-heap-value-typeshttp://www.codeproject.com/Articles/76153/Six-important-NET-concepts-Stack-heap-value-types
In .NET depending on the data type, the variable is either assigned on the stack or on the heap.
‘String’ and ‘Objects’ are reference types,
and any other .NET primitive data types are assigned on the stack. The figure below explains the same in a more detail manner.
=========================================================================
http://antrash.pixnet.net/blog/post/70456505-stack-vs-heap%EF%BC%9A%E5%9F%B7%E8%A1%8C%E6%99%82%E6%9C%9F%E5%84%B2%E5%AD%98%E5%85%A9%E5%A4%A7%E8%A6%81%E8%A7%92
現 代電腦系統大多依照Von Neumann Architecture設計而成,其中一特色stored programming乃指
『程式執行一定要將欲執行的指令跟資料放入記憶體方可執行』,由此可知執行過程中記憶體所佔的地位厥偉之處。
但許多工程師卻搞 不清楚記憶體中的stack跟heap space到底有何居別,下面簡單針對兩者加以論述,希望對讀者有所幫助~
三分天下。程式執行過程中其實主要分成三大區塊:global、stack、heap三塊。其中global區塊最最易理解,主要存放全域變數或宣告為static的靜態變數在此就不多做贅述;
另外兩個區塊分別為stack跟heap這兩者往往混淆不清,尤其在java中有時候會出現stack overflow或heap overflow到底兩者差異在哪,
若工程師連這都不清楚那以後怎麼去調整JVM中的heap memory space跟stack memory space的大小呢?
貼心的系統全自動化管理區塊:Stack Memory Space!在記憶體中不外乎就是要存放變數、函式相關資訊等資料,使運作過程可以順利取得所需的變數或函式所在地。
要讓系統可以全自動化管理,代表需可被預期此變數或函數資訊的生命週期,一旦完全可預測代表可以安心的交由系統管理,這些資訊也將在執行過程中被存放在stack空間。
Stack中常見的存放資訊如下:區域變數(local variable)、函式參數(function/method parameter)、函數的返回位址(function/method return address)等資訊。為何上述資訊會放於stack之中,簡單來說:
void method1() {
int x = 100;
}
上述的int x = 100,系統會在stack中找一個區塊給x,另外裡面的內容為100。然而,x會被放入stack主要是因為在編譯時期系統已經可以預知x從何時開始配置跟何時結束回收(當然就是看所屬block結束就跟著回收),
由於配置跟回收的規則明確,當然就往stack擺囉。
在舉一例子:
void method2() {
method1();
}
上述當呼叫method1()時,系統會先把method2的返回位址存到stack當中,為何是存放在stack呢,因為函式的呼叫有後進先出的概念,當method1()被呼叫而開始執行,
待結束時必定會查找該返回何處,故最後一定會讀取函式的返回位址,既然如此明確而有條理,當然也是往stack放!
可預測性外加後進先出的生存模式,令stack無疑是最佳的存放策略。由於程式語言中變數跟函式的生命週期皆為後進先出的概念,也就是越晚產生的會越先被回收或銷毀。
正因如此只要是可預測性的相關資訊都是往stack存放。此外,由於stack中的資料之存活週期規律故由系統自行產生與回收其空間即可,就不勞工程師們費心啦!
天啊!程式中竟然有不可預測其存活時間的資料存在。在程式中,有部分的需求總是在執行中依據實際情況才會動態增減,這些資訊是難以被預測哪時候開始有?量有多少?
何時該回收?…這些不可預測的因素造成上述的stack區塊不適合運用於此。當資訊為動態配置產生,
系統會存放在另外一塊空間,稱之為『Heap』(注意這裡的Heap跟資料結構中的Heap不相關,可別會錯意!)。
Heap的區塊專收執行期間動態產生的資料,由於為動態產生故結束點無法由系統來掌握,故需使用者自行回收空間。在C++或Java中利用new語法產生的就是動態配置的物件,需存放於heap中。
奇怪跑越久記憶體用越多的怪現象。許多時候執行的程式都沒有改變,但卻常出現隨時間執行越久程式所耗用的空間將越多,最後造成out of memory。
工程師也不知為何如此,就是定期在out of memory之前restart程式即可。這中現象層出不窮,一般大多是因為工程師沒有正確將記憶體回收所導致。
Heap中的資料如果沒有正常的回收,將會逐步成長到將記憶體消耗殆盡,下次發生上述問題的實後,切記自己檢查一下heap空間的資料有無正常回收。
論述到此有些讀者可能會覺得納悶:為何在寫Java都不需要注意回收空間的問題?~答案是因為Java中會採用Garbage Collection(垃圾回收)的機制自動檢查Heap中哪些資料已經沒有被使用,
當確認資料已經沒有使用會自動將空間回收,如此工程師就專注撰寫程式即可,不用擔心記憶體回收不當等問題。
The conclusion is…。當產生stack overflow一般是因為過多的函式呼叫(例如:遞迴太深)、或區域變數使用太多,此時請試著將stack size調大一點,
另外檢查看看函式的呼叫跟變數的使用量。反之,當發生heap overflow請檢查是否都有正確將heap space的資料回收,另外採行的動態配置是否合理,
不要過渡濫用而new出無謂的空間,若真的是程式過於複雜造成,請將heap size調大一些。
=========================================================================
http://neo_lin_42.blog.ithome.com.tw/post/620/6564
http://dascan.pixnet.net/blog/post/15459902-%E5%A0%86%28heap%29%E5%92%8C%E6%A3%A7%28stack%29
http://xingulin.tumblr.com/post/48493582986/ref-type-vs-val-type
在 MSDN 上,將 .Net 下所有的類別,分為以下三類︰
也就是說,Value Type 與 Reference Type 最顯著的差別,是他們在記憶體中,儲存其變數值的方式。再往下繼續探討前,我覺得我們可以先建立以下的基礎觀念︰
資料型別與記憶體配置
當執行.NET程式時,若遇到變數宣告的敘述,CLR會根據其資料型別為此變數進行記憶體配置。
若此變數的型別是數值型別(value type),則CLR會在堆疊(stack)上配置一塊適當的空間。
當指定一個值給變數時,變數的值是直接存放在stack上,如下圖所示。
若此變數的型別是參考型別(reference type),則CLR同樣會在stack上配置一塊適當的空間。
當初始化時,CLR會在堆積(heap)配置一塊適當的空間來存放新建的物件,
並將物件的參考位址傳回存放在stack上,如下圖所示。
由此可知,當宣告一個變數時,CLR會在stack上配置一塊空間,只不過存放的值不一樣。
若是數值型別,則此空間會存放變數的值;若是參考型別,則是存放其物件在heap上的參考位址。
但這種作法並不適用於類別的變數(稱為欄位field)。在類別中宣告的變數為數值型別,則其值是存放與物件相同的heap空間;
在此物件中宣告的變數為參數型別,則CLR是在存放與物件不同的另一塊heap空間。
當建立新的物件時,此時若記憶體空間不足,則CLR會啟動Garbage Collector,對這些garbage進行回收,
釋放其佔用的空間。然後移動存活物件以覆蓋garbage原佔用的空間,使其緊密排列。最後再修正存活物件的參考位址。
Garbage Collector並不是在物件參考無效時就立即開始回收,而是根據演算法來決定什麼時候進行回收和對什麼物件進行回收。
在.NET程式中可以使用GC類別與Garbage Collector進行互動。您可以呼叫GC類別的Collect方法強制回收garbage。常用模式如下:
GC類別的使用
在.NET程式中可以使用GC類別與Garbage Collector進行互動。您可以呼叫GC類別的Collect方法強制回收garbage。常用模式如下:
GC.Collect();
GC.WaitForPendingFinalizer();
GC.Collect();
堆(heap)和棧(stack)的對比
從 以上知識可知,
棧是系統提供的功能,特點是快速高效,缺點是有限制,數據不靈活;
而堆是函數庫提供的功能,特點是靈活方便,數據適應面廣泛,但是效率有一 定降低。
棧是系統數據結構,對於進程/線程是唯一的;堆是函數庫內部數據結構,不一定唯一。
不同堆分配的內存邏輯上無法互相操作。
棧空間分靜態分配和動態 分配兩種。靜態分配是編譯器完成的,比如自動變量(auto)的分配。動態分配由alloca函數完成。
棧的動態分配無需釋放(是自動的),也就沒有釋放 函數。為可移植的程序起見,棧的動態分配操作是不被鼓勵的!
堆空間的分配總是動態的,雖然程序結束時所有的數據空間都會被釋放回系統,但是精確的申請內存 /釋放內存匹配是良好程序的基本要素。