摘要:采用C#語言進行編程的時候,程序員不用對內(nèi)存管理過多的關心,對內(nèi)存產(chǎn)生的垃圾文件垃圾收集器會自動進行清理。當然, 對于一些高質量的代碼編寫,還是要對后臺處理有所了解,清楚C#編程內(nèi)存管理的一些原理及問題。本文主要是根據(jù)內(nèi)存管理的一些內(nèi)容進行分析,并對其管理過程中的一些問題進行處理。
關鍵詞:C#編程;內(nèi)存管理;堆棧;托管堆
中圖分類號:TP312.1 文獻標識碼:A 文章編號:1007-9599 (2012) 20-0000-02
對于C#編程而言,其主要是把數(shù)據(jù)分為兩個類型,引用數(shù)據(jù)類型和值數(shù)據(jù)類型,在內(nèi)存管理中,這兩類數(shù)據(jù)存儲的位置是不同的,引用數(shù)據(jù)類型主要存儲于內(nèi)存的托管堆中,而值數(shù)據(jù)類型主要存儲于堆棧中。
1 C#編程中內(nèi)存管理的主要內(nèi)容
一般而言,采用虛擬尋址系統(tǒng)將程序中可用地址通過映射存儲于內(nèi)存中的實際地址上。對于硬件內(nèi)存而言,其存儲的方式都是由零開始向上遞增存儲,所以,如果要對內(nèi)存中某一單元進行訪問時,必須要有表示該存儲單元的地址。在高級編程語言下,編譯器最主要是作用之一就是要把可以理解的變量名改變?yōu)樘幚砥骺梢岳斫獾呐c之相對應的內(nèi)存地址。
1.1 堆棧。這是內(nèi)存中的一個區(qū)域名稱,主要用于存儲值數(shù)據(jù)類型,在存儲對象中,值數(shù)據(jù)類型進行調(diào)用時,首先將調(diào)用的所有方法傳遞到參數(shù)副本,在選擇調(diào)用方法時,堆棧中存儲的所有參數(shù)其實均為副本,所以在將值類型A傳遞到函數(shù)的過程中,A值是不會發(fā)生改變的。這與引用類型是不同的,引用類型一般會發(fā)生改變,主要是由于堆棧中所存儲的是引用類型地址。
1.2 托管堆。由于堆棧的功能強大,且性能相當高,但是其不足之處是變量的生命周期要求應該為嵌套,所以在對部分數(shù)據(jù)進行存儲的時候過于苛刻。在此基礎上產(chǎn)生了一種新的內(nèi)存分配方式,即托管堆,該方法對部分數(shù)據(jù)的存儲,并且保證了方法退出以后,在相當長的一段時間內(nèi),這些數(shù)據(jù)依然可以使用。該方法也簡稱為堆,是在內(nèi)存中的另外一個區(qū)域內(nèi)進行工作的。例如:
{
Customer customer1;
Customer1=new Customer()
Customer customer2= new Customer();
}
首先,聲明一個Customer是customer1,然后在堆棧上對其進行存儲分配。這里只是對其進行分配存儲空間的引用,不是實際的對象,通過customer1占用的4字節(jié)空間對Customer對象在內(nèi)存中的地址進行表示。進而執(zhí)行第二行代碼并完成操作。根據(jù)此例可以看出,引用類型的變量要比值類型變量建設過程復雜很多,且其性能下降的現(xiàn)象也不可避免。但是,可以采用將一個引用變量的值賦予另一個引用變量,其中一個出了作用域時,另一個會自動刪除,而對象數(shù)據(jù)仍然存儲在內(nèi)存中,直到程序停止才會消失。如果將引用變量A傳遞給函數(shù),也只是將變量A的引用進行了傳遞,換言之,也只是在堆棧上進行了內(nèi)存的分配,即變量B,A和B所指向的內(nèi)存地址是相同的,如果B改變,那么A也會隨之改變。
1.3 裝箱及拆箱。在將值數(shù)據(jù)類型與引用數(shù)據(jù)類型項目相互進行轉化的時候主要采用裝箱及拆箱的方法,裝箱的過程是將值數(shù)據(jù)類型轉換為引用數(shù)據(jù)類型,拆箱則相反,是將引用數(shù)據(jù)類型轉換為值數(shù)據(jù)類型。
1.4 垃圾收集。一般而言,NET運行庫在運行一段時間以后,會自動的將系統(tǒng)所產(chǎn)生的垃圾信息收集到垃圾收集器中,釋放托管的資源,這在多數(shù)情況下能很好的解決垃圾信息占用大量內(nèi)存的情況。然而對于一些特殊情況時,就需要垃圾回收器強制性的在代碼的某一處進行內(nèi)存的釋放,這個時候就要用到System.GC,即垃圾收集器。垃圾收集器最主要的用處是在代碼中存有大量的對象,在這些對象剛停止引用時使用。就堆棧和托管而言,首先堆棧填充的方向是向下,即從高內(nèi)存地址向低內(nèi)存地址存儲,其工作原理是先將內(nèi)存變量進行分配,然后再進行內(nèi)存釋放,采用的是先進后出的原則,自下而上的對變量進行釋放,這種工作原理主要是為了保證堆棧的運行規(guī)則與其變量的生命周期不會發(fā)生矛盾與沖突。但是由于其性能過高造成的變量不夠靈活的問題,人們都希望通過另外一種方法對內(nèi)存進行分配,保證數(shù)據(jù)的存儲及方法退出后數(shù)據(jù)在一定時間段內(nèi)依然可以使用,托管堆的引入很好的解決了這一問題,該堆主要是指在.NET中,垃圾收集器進行自動管理,這與堆棧是完全不同的,托管堆采用自下向上的分配原則,將自有空間全部置于已用空間的上部。
2 C#編程中內(nèi)存管理的主要問題
內(nèi)存分配是內(nèi)存管理的第一個步驟,如何對其進行正確的分配,直接關系到程序運行的正確與否,因此必須對內(nèi)存分配認真的對待。需要注意的是,在內(nèi)存進行動態(tài)的分配過程中,是最容易出現(xiàn)問題的環(huán)節(jié),所以在進行內(nèi)存管理的時候,要對內(nèi)存的動態(tài)分配過程更加的重視,本文主要對內(nèi)存管理過程中的問題從以下幾個方面進行研究分析:
(1)采用new或者malloc完成內(nèi)存的申請以后,要馬上檢查指針,查看其是否為NULL。要防止將指針值為NULL的內(nèi)存進行使用。假設指針p是函數(shù)的參數(shù),此時采用函數(shù)入口處通過if或者assert作為防錯處理的措施。(2)對動態(tài)內(nèi)存以及數(shù)組進行賦初值。主要是為了防止把沒有經(jīng)過初始化的內(nèi)存作為右值使用,對于內(nèi)存的缺省初值的研究在目前來說還沒有一個統(tǒng)一的標準進行規(guī)范,所以在數(shù)組的創(chuàng)建過程中,不管采用什么樣的方法都要重視賦初值,這樣就避免了指針自動指向NULL,防止“野指針”現(xiàn)象的出現(xiàn)。(3)避免指針或者數(shù)組的下標越界。在具體的操作過程中,要小心發(fā)生“少1”或者“多1”等操作。在對數(shù)組進行使用的時候,常常會出現(xiàn)下標“少1”或者“多1”的操作現(xiàn)象。尤其在for循環(huán)語句中,由于循環(huán)的次數(shù)較多,因此很容易就會給搞錯,最終造成整個數(shù)組在操作的過程中發(fā)生越界的現(xiàn)象。所以,在具體的操作過程中,要求程序員在編寫程序的時候要認真,編寫完成以后要仔細的進行檢查。(4)動態(tài)內(nèi)存的申請與釋放。為防止內(nèi)存泄露現(xiàn)象的發(fā)生,要求動態(tài)內(nèi)存的申請和釋放必須是配對的,一旦忘記了內(nèi)存的釋放,內(nèi)存就會出現(xiàn)泄露現(xiàn)象。如果函數(shù)中存在此錯誤,那么該函數(shù)在被調(diào)用的過程中,就會丟失一塊內(nèi)存,且每次都是一樣。在最初,系統(tǒng)內(nèi)存較為充足,此時很難發(fā)現(xiàn)錯誤,但經(jīng)過一段時間的使用以后,會出現(xiàn)程序突然死掉的情況,這時系統(tǒng)提示內(nèi)存已耗盡,這就是為什么在大多數(shù)的初學者中出現(xiàn)的機器速度越來越慢,進而出現(xiàn)頻頻死機的一個原因。所以要對動態(tài)內(nèi)存的申請和釋放配對進行,在程序中所體現(xiàn)的malloc和free二者使用次數(shù)也應該是相同的,如果不同,肯定出現(xiàn)了錯誤,同理delete和new也是一樣的。(5)delete和free在完成內(nèi)存釋放以后,要馬上將指針設置到NULL,防止出現(xiàn)“野指針”的現(xiàn)象。例如一個指針p經(jīng)過delete或者free以后,如果沒有將其設置為NULL,那么往往指針p會被認為是合法的指針,但是實際情況是,該指針所傳達的只是前一個內(nèi)容的指示,在目前其僅僅是作為“垃圾”信息存在。
3 結束語
對內(nèi)存的管理,很難用一篇文章來完整的進行闡述,因此本文主要對C#編程中內(nèi)存管理的內(nèi)容及常見的問題進行簡單的分析和闡述,對于編程工作者而言,要對內(nèi)存分配、回收等相關知識進行掌握。總而言之,對于常見的內(nèi)存管理中的問題,可以根據(jù)本文所闡述的幾個解決方法進行解決,以避免不可預測的錯誤發(fā)生。只有這樣才能對內(nèi)存的使用更加的合理,編寫的程序才能高效的運行。
參考文獻:
[1]韓耀堂.C#編程中的內(nèi)存管理不該忽略的問題[J].計算機光盤軟件與應用.2011(13).
[2]陳鄭軍,游蓮.淺析C#動態(tài)內(nèi)存管理機制[J].重慶廣播電視大學學報,2008(06).
[3]凌建輝.淺析C#編程中的內(nèi)存管理[J].科技資訊,2009(12).