Re: [問題] 為何還有結構存在?
同討論串前一篇的講法很一知半解(或者說,其實連正解的五分之一都不到),
且聽我道來。
作業系統配置記憶體給應用程式後,應用程式要怎麼使用這些記憶體,
基本上都是應用程式自己的事務,作業系統不會去干涉的。
就一般應用程式架構設計來說,會把作業系統下來的記憶體分為幾類:
程式碼空間,堆疊,靜態資料,堆積;在台灣一般學校裡傳授使用MASM的
16-bit X86組合語言裡,宣告段落時,對應的只有前三樣,.code,.stack,
.data,嚴格說來,.data就同時包含了靜態資料與堆積。去問只會組語而不
明白高階程式語言程式中記憶體配置機制的人,得到不知道堆積heap是什麼
的答案也不奇怪。
先講原生機械碼平台上的情形:
一般高階語言寫出來的程式,編譯好後,程式中編譯前定義的靜態資料佔用的
記憶體空間都是固定的,但是程式中動態配置的記憶體仍然要佔用空間。這些
不見得會被持續佔用著,也不見得是固定大小的,通通由保留給heap的記憶體
空間來支應。在高階語言程式中會有編譯器廠商提供包含heap manager的執行
期程式庫,由裡頭的heap manager來應付程式語言中對動態記憶體配置與釋放
的要求。配置給程式作為動態記憶體塊使用的記憶體空間,會從heap中的可用
空間被劃分出來,標示為已使用,不可以被重複配置給其他動態記憶體配置要
求,直到這個動態記憶體塊被釋放,heap manager才會再把它列入可用空間中。
如Visual C++、Borland C++、Delphi,雖然各個編譯器的heap manager設計
各有出入,大體上都是用linked list在管理這些大大小小的可用空間跟已配置
記憶體塊。以C++為例,物件的記憶體配置,auto的都是來自stack,static的
來自靜態資料空間,dynamic的就都是執行期從heap動態配置出來的,所有new
出來的物件都是動態物件,都從heap配置記憶體。
Stack中是不會放任何程式編譯好時就預先定義好的資料的,學過組語的人會講
「早期的C, 程式一開始即宣告好的字串就是 Stack了」,實在是有嚴重誤解
啊。也許你可以設計一個編譯器,刻意把宣告好的字串放在stack裡頭,但是
後果會如何,只要遞迴次數夠多次、stack的區域變數佔用的空間夠大,就很
清楚了。
細節不深入太多。但是這樣子的設計衍生出來的一個程式維護性問題是,凡是
被配置出來的動態記憶體塊,最後都要被釋放,才能夠再給其他的動態記憶體
配置要求所使用。如果這些動態配置出來的記憶體都沒釋放,即使程式中已經
不再參考使用這些記憶體塊,它們也不能被回收使用。相對的,如果一個記憶
體塊還被參考使用著,卻因為程式設計者的疏忽而被釋放,然後被其他動態記
憶體配置要求所使用,就會發生存取錯誤資料的情形。所以才衍生出GC來。
在原生機械碼平台上有GC的程式開發環境沒有成為顯學,但是Java/.NET在設
計時把GC當成了預設行為。有GC後,寫程式還是要跟heap manager打交道,但
是釋放動態配置記憶體的問題由GC去默默收拾了。寫程式的人也許會忘記釋放
一塊記憶體,但是大部分情形下,對一塊記憶體的參考指標在離開一定的scope
後就會無效,這種事情可以由編譯器負責收拾,不需要寫程式的人刻意為之。
以前沒有GC時,一塊記憶體從heap被配置出來,heap manager多半會在它旁邊
保留幾個byte來記憶下一塊被配置記憶體或可用記憶體的位置,作為heap內部
管理用的linked list pointer,也多半會再多保留幾個byte來記錄別的內部
資訊。GC繼續延用這樣的機制,但是會要求更多空間來記錄GC機制內部使用的
資訊,所以動態配置記憶體的代價比起沒GC時要更大。
比較起來,直接使用stack的auto變數/物件,包括C#設計上刻意為之的16 bytes
大小以下的struct,都不用經過heap manager配置記憶體空間,也不必經由GC回
收記憶體,而是由編譯器在編譯時就算好該用多大的堆疊空間,直接在function/
method code被呼叫時就從堆疊中保留那樣大的空間出來用。不用花時間讓heap
manager去找適當大小的可用記憶體塊來配置,也不用花時間等GC收完垃圾,所以
效能好。
※ 引述《virdust2003 (替機殼洗個熱水澡)》之銘言:
: 就我所知, heap 可以看成一塊亂糟糟的 記憶體
: 物件的東東都是存在這裡,也就是隨便挖一塊記憶體去放,所以會有很多空格
: 但是我們以前學的不都是需要一個 SP or BX (忘了是什麼了) 來取得 參數
: 但是物件需要一個指標,也就是那塊長長的記憶體位置存的都是物件的位址
: ^^^^^^^^^^^^附註
: 所以要存取物件的值的話,總共需要存取兩次記憶體。但Stack 裡面只需要32Bit就好
: 但若宣告的是 Struct 的話,例如 Point ,那麼 x,y 就是直接放在 Stack 裡面
: 存取的話,直接用暫存器加減X就可以取得了,也就是一次KO~
: 不知道這樣說的明白嗎?
: PS:曾問過我的組語老師,Heap相關問題,他回說:「Heap是什麼?」
: 所以也有可能 Heap 是GC出來之後的產物
: 至於 16byte以下用 Struct效率比較好,是在TechEd 2004 聽到蔡學鏞講的~
: 物件導向的語言 其字串也是放在 Heap 中,所以每次指派才都會多出一塊垃圾記憶體~
: 但若早期的C, 程式一開始即宣告好的字串就是 Stack了~
: 動態的話,我想應該也叫做Stack ,因為那時候沒有gc可以幫你回收 ,都要自己free 掉
: 附註:
: 長長的記憶體指的是 Code從上面開始,Data從下面開始,以前學組語的那種模型
: 所以Data太多還會蓋到 Code ,我覺得還滿好笑的~
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.222.17.194
※ 編輯: Aurim 來自: 61.222.17.194 (07/13 14:16)
推
140.111.79.32 07/13, , 1F
140.111.79.32 07/13, 1F
推
08/10 16:55, , 2F
08/10 16:55, 2F
→
08/10 16:56, , 3F
08/10 16:56, 3F
討論串 (同標題文章)
C_Sharp 近期熱門文章
PTT數位生活區 即時熱門文章
20
55