Re: [問題] 為何還有結構存在?

看板C_Sharp (C#)作者 (替機殼洗個熱水澡)時間20年前 (2005/07/13 15:37), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串6/7 (看更多)
※ 引述《Aurim (Who cares?)》之銘言: : 同討論串前一篇的講法很一知半解(或者說,其實連正解的五分之一都不到), : 且聽我道來。 : 作業系統配置記憶體給應用程式後,應用程式要怎麼使用這些記憶體, : 基本上都是應用程式自己的事務,作業系統不會去干涉的。 : 就一般應用程式架構設計來說,會把作業系統下來的記憶體分為幾類: : 程式碼空間,堆疊,靜態資料,堆積;在台灣一般學校裡傳授使用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的區域變數佔用的空間夠大,就很 : 清楚了。 不好意思,我手邊沒書,但 Load的時候 不是會要到一塊長長的記憶體, 接下來 Linker 把 Data(一開始宣告好的)、Code從頭開始填入, 然後 SP 指到最後的位址, 這裡我是把 那塊長長的記憶體稱為 Stack,這樣有錯嗎? 還是你指的Stack 是另外一個Frame,所以才有差別, 可是早期的時候不是只有一個Frame嗎?(.com的情況) 沒想到會在C#版討論這個^^~ : 細節不深入太多。但是這樣子的設計衍生出來的一個程式維護性問題是,凡是 : 被配置出來的動態記憶體塊,最後都要被釋放,才能夠再給其他的動態記憶體 : 配置要求所使用。如果這些動態配置出來的記憶體都沒釋放,即使程式中已經 : 不再參考使用這些記憶體塊,它們也不能被回收使用。相對的,如果一個記憶 : 體塊還被參考使用著,卻因為程式設計者的疏忽而被釋放,然後被其他動態記 : 憶體配置要求所使用,就會發生存取錯誤資料的情形。所以才衍生出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 ,我覺得還滿好笑的~ -- ----------------------------------------------------------------------------- 功課重,Project多的好幫手--專案王 http://steven.twbbs.org/ProjectKing 增加右鍵的威力RightMenuKing--右鍵王 http://steven.twbbs.org/RightMenuKing/ 備份重要檔案的好幫BackupKing--備份王 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.113.164.5
文章代碼(AID): #12rCJ2fC (C_Sharp)
討論串 (同標題文章)
文章代碼(AID): #12rCJ2fC (C_Sharp)