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