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

看板C_Sharp (C#)作者 (Who cares?)時間20年前 (2005/07/13 13:12), 編輯推噓2(201)
留言3則, 2人參與, 最新討論串5/7 (看更多)
同討論串前一篇的講法很一知半解(或者說,其實連正解的五分之一都不到), 且聽我道來。 作業系統配置記憶體給應用程式後,應用程式要怎麼使用這些記憶體, 基本上都是應用程式自己的事務,作業系統不會去干涉的。 就一般應用程式架構設計來說,會把作業系統下來的記憶體分為幾類: 程式碼空間,堆疊,靜態資料,堆積;在台灣一般學校裡傳授使用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
咦 原來是2005年的文XD
08/10 16:56, 3F
文章代碼(AID): #12rAB9FL (C_Sharp)
討論串 (同標題文章)
文章代碼(AID): #12rAB9FL (C_Sharp)