# 記憶體配置,什麼是 Stack、Heap? ###### tags: `記憶體` `Stack` `Heap` * [何謂Stack、Heap 有何用處?](#何謂stack-heap-有何用處?) * [影片教學](#影片教學) * [練習講解](#練習講解) * [多執行緒](#程序、執行緒、多執行緒) * [結論](#結論) ## 何謂stack, heap 有何用處? * Heap 動態(堆積, 堆) * 不可預測其存活時間的資料 * 資訊為動態配置產生 * 由於為動態產生故結束點無法由系統來掌握,故需使用者自行回收空間 * Stack 靜態(堆疊, 棧) * 可預測性 * 後進先出的生存模式 * stack中的資料之存活週期規律故由系統自行產生與回收其空間即可 * 常見的存放資訊: * 區域變數(local variable) * 函式參數(function/method parameter) * 函數的返回位址(function/method return address ) ![](https://paper-attachments.dropbox.com/s_C3616668CC417F6E9665F366095A42DE3203FFDE10D7BA800CCD2123FEB0CDA1_1483971822225_.png) ## 影片教學 https://www.youtube.com/watch?v=450maTzSIvA& https://youtu.be/450maTzSIvA ## 練習講解: 問題程式碼如下: ``` public main(){ Foo foo = new Foo(); foo.doA(); foo.doB(); } public class Foo { int a; int b; public class Foo(){ } public void doA(int c; int d){} public void doB(int e int f){} } ``` 講解順序步驟: Step 1. ``` public main(){ Foo foo = new Foo(); ``` | Stack| Heap| | -------- | -------- | | foo | | Step 2. ``` public main(){ Foo foo = new Foo(); ``` | Stack| Heap| | -------- | -------- | | foo |Foo() a, b | Step 3. ``` public main(){ Foo foo = new Foo(); foo.doA(); ``` | Stack| Heap| | -------- | -------- | | doA c,d | | | foo |Foo() a, b | Step 4. ``` public main(){ Foo foo = new Foo(); foo.doA(); foo.doB(); ``` | Stack| Heap| | -------- | -------- | | doA e,f | | | doA c,d | | | foo |Foo() a, b | | | | class | Stack | Heap | | - | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | --------- | | 1 | void main() <br>{<br>} | | main | | | 2 | void main()<br>{<br> Foo foo=new Foo()<br>} | class Foo<br>{<br> int A<br> int B<br>} | main foo | foo→ A B | | 3 | void main()<br>{<br> Foo foo=new Foo()<br> foo.DoA()<br>} | class Foo<br>{<br> int A<br> int B<br> void DoA()<br> {<br> int C<br> int D <br> }<br>} | DoA C D<br>main foo | foo→ A B | | 4 | void main()<br>{<br> Foo foo=new Foo()<br> foo.DoA()<br>} | class Foo<br>{<br> int A<br> int B<br> void DoA()<br> {<br> int C<br> int D <br> DoB() <br> }<br> void DoB()<br> {<br> int E<br> int F <br> }<br>} | DoB E F<br>DoA C D<br>main foo | foo→ A B | | 5 | | | DoA C D<br>main foo | foo→ A B | | 6 | | | main foo | foo→ A B | | 7 | | | | A B | | 8 | | | | | 另外同一樣在stack內又有區分 ![](https://paper-attachments.dropbox.com/s_C3616668CC417F6E9665F366095A42DE3203FFDE10D7BA800CCD2123FEB0CDA1_1484822989070_JVM-Stack.png) 2. 1 thread v.s. 2 threads? ![](https://paper-attachments.dropbox.com/s_C3616668CC417F6E9665F366095A42DE3203FFDE10D7BA800CCD2123FEB0CDA1_1484190397148_file.png) ![](https://paper-attachments.dropbox.com/s_C3616668CC417F6E9665F366095A42DE3203FFDE10D7BA800CCD2123FEB0CDA1_1484190437433_file.png) ## 程序、執行緒、多執行緒 * 程序(process) 當一個程式在電腦執行時會先向系統進行註冊,讓系統將這個程式記錄在它的執行清單上,系統此時會將這程序標上一個唯一的ID以作為區別,即PID(Process ID),並分配適當的資源給這個程式來進行工作,這些資源包含CPU的使用權以及獨立的資料儲存空間,我們稱此動作為建立一個處理程序(process)。每個程序所擁有的資源在執行期間是獨佔的,不與其它程序共用,所以每個程序只能存取屬於自己的部份,不能直接去更改其它程序的資料,如果程序間需要交流,必須建立通訊的管道才能交換情報。另外,因為CPU的數目有限而待執行的程序可能有很多個,因此系統會為每個程序規劃出一段CPU使用時間,在這段時間內分配給這個程序的CPU就專屬於該程序而不會去處理其它程序的工作。 * 執行緒(thread) 執行緒是系統處理工作的基本單元,通常一個CPU在同一時間只能提供一個執行緒(在此不考慮Hyper-Threading技術),讓系統調用去執行程式。程序跟執行緒間的關係我們可以把它想像成是工廠與員工的關係,工廠擁有資源與設備但需要由員工去操作才能生產產品,所以要做出一件成品,工廠內至少要有一位員工在做事,不同的程序就像是不同的工廠,而執行緒像是一位派遣員工一樣,由作業系統負責調度他在什麼時間該去那家工廠上班,如果電腦擁有多個處理核心,即代表系統可以同時調用多個員工。 * 多執行緒(multi-threading) 延續剛剛工廠、員工的比喻,系統可以同時間內把多個員工派到同一家工廠去工作,此法稱做多執行緒(multi-threading)平行執行,相較於單一執行緒處理方式,它有機會讓工作在比較短的時間內完成,多執行緒工作時,隸屬同一程序下的所有執行緒會分享該程序的所有資源,此外各執行緒彼此間也可以擁有自己私有的資源,而不與其它同一程序內的執行緒共用。這就像是工廠內的公共設備是所有員工可以自由使用一樣,但每個員工也都會有自己的工作空間與置物櫃可以擺放自己私人的物品。 ## 結論 - 擁有多CPU的電腦系統可以同時處理多項程序或將單一程序平行處理。 - 一個程序被執行時至少要有一個執行緒,但也可同時擁有多個執行緒來進行處理。 - 程序間的資源是彼此獨立不共用的。 - 同一程序下的所有執行緒分享該程序的所有資源,而執行緒之間也能夠擁有彼此獨立的資源。