發(fā)文章
發(fā)文工具
撰寫
網(wǎng)文摘手
文檔
視頻
思維導圖
隨筆
相冊
原創(chuàng)同步助手
其他工具
圖片轉(zhuǎn)文字
文件清理
AI助手
留言交流
本次日志,我們來重點聊一聊軟件開發(fā)過程中,如何提高性能方面的問題。這是軟件開發(fā)或研發(fā)過程中深層次的問題,這篇文章主要從內(nèi)存分配和內(nèi)存回收兩方面說明,我們軟件代碼編寫過程中,計算如何來工作的。在此你可以了解內(nèi)存管理的過程和方式,以便在以后的軟件開發(fā)中注意它、利用它。
值類型包括:int,float,double,bool,結(jié)構(gòu),引用,表示對象實例的變量
引用類型包括:類和數(shù)組;比較特殊的引用類型string、object
一般情況下:值類型存儲在堆棧中(不包括包含在引用中的值類型,如類的值字段,類中的引用字段,數(shù)組的元素這些都是隨引用存儲在受管制的堆中);引用類型存儲在受管制的堆中,為什么說是受管制的堆,下面會具體來談。
幾個概念:
虛擬內(nèi)存:32位的計算機,每個進程擁有4G的虛擬內(nèi)存。
受管制的堆(托管堆):受誰的管制?當然是無用單元收集器,即垃圾收集器。如何管理下面再說?
無用單元收集器:垃圾收集器除了會壓縮托管堆、更新引用地址、還會維護托管堆的信息列表等等。
關于值類型的存儲先看如下代碼:
{
int age=20;
double salary=2000;
}
上面定義的兩個變量,int age,告訴編譯器需要給我分配4個字節(jié)的內(nèi)存空間來存儲age值,它是存儲在堆棧上的。堆棧屬入先進后出的數(shù)據(jù)結(jié)構(gòu),堆棧是從高位地址到低位地址存儲數(shù)據(jù)的。計算機寄存器中保持著一個堆棧指針,他總是指向堆棧最底端的自由空間地址,當我們定義一個int類型的值時,堆棧指針遞減四個字節(jié)的地址;當變量出了作用域后,堆棧指針相應的相應的遞增四個字節(jié)的地址,它只是堆棧指針的上下移動,所以堆棧的性能是相當高的。
下面看一下引用類型的存儲,還是先看代碼:
Customer customerA;
customerA=new Customer(); //假定Customer實例占據(jù)32個字節(jié)
上面的代碼第一行先聲明了一個Customer引用,引用的名字為customerA,在堆棧上給此引用分配存儲空間,存儲空間的大小為4個字節(jié),因為它只存儲了一個引用,這個引用所指向的才是即將存儲Customer實例的空間地址,注意此時customerA并沒有指向具體的空間,它只是分配了一個空間而已。
第二行執(zhí)行過程中,.net環(huán)境會搜索托管堆,尋找第一個未使用的、連續(xù)的32個字節(jié)空間分配給類的實例,并設置customerA指向這段空間的頂端位置(堆的空間是從低到高使用的)。當引用變量出作用域后,堆棧中的引用會無效,當托管堆中的實例還在,直到垃圾收集器對其進行清理。
到這里細心的讀者可能會有些疑問,是不是定義引用類型時,計算機要搜索整個堆,尋找足夠大的內(nèi)存空間來存儲對象呢?這樣會不會效率很低?如果沒有足夠大的連續(xù)的空間呢?這個就要談到“托管”了。堆是受垃圾收集器管理的,.net在執(zhí)行垃圾收集器時釋放能釋放的所有對象,并壓縮其他對象,然后把所有自由空間組合在一起移動到堆的頂端, 形成連續(xù)的塊,同時更新其他移動對象的引用。如果再有對象定義,可以很快找到合適的空間。如此看來托管堆工作方式與堆棧類似,它是通過堆指針來完成空間的分配和回收的。
上面談了.net對內(nèi)存空間分配的管理過程和方式,接下來談一談對內(nèi)存的回收過程。談到資源的清理,不得不提到的兩個概念和三個方法。
兩個概念為:托管資源和非托管資源。
托管資源接受.net framework的CLR(通用語言運行時)的管理;非托管資源則不受它的管理。
三個方法為:Finalize(),Dispose(),Close()。
一、Finalize()為析構(gòu)方法,清除非托管資源。
在類中定義方式:
public ClassName{
~ClassName()
//清理非托管資源(如關閉文件和數(shù)據(jù)庫聯(lián)接等)
它的特點是:
1. 運行不確定性。
它是受垃圾收集器的管理,當垃圾收集器工作時,會調(diào)用此方法。
2. 性能開銷大。
垃圾收集器工作方式為,對象如果執(zhí)行了Finalize()方法,垃圾收集器第一次執(zhí)行時,會把它放在一個特殊的隊列中;第二次執(zhí)行的時候才會刪除此對象。
3. 不能顯示定義和調(diào)用,定義為析構(gòu)方法形式。
基于以上特點,最好不要執(zhí)行Finalize()方法,除非類確實需要它或與其他兩個方法結(jié)合來用。
二、Dispose()方法,可清除一切需要清除的資源,包括托管和非托管資源。
定義如下:
public void Dispose()
//清理應該清理的資源(包括托管和非托管資源)
System.GC.SuppressFinalize(this); //這一句很重要,下面會解釋原因。
它的特點:
1. 任何客戶代碼都應顯示調(diào)用這個方法,來釋放資源。
2. 由于第一點的原因,一般要做一個備份,這個備份一般由析構(gòu)方法來擔任角色。
3. 定義此方法的類,必須繼承IDisposable接口。
4. 語法關鍵字using等同于調(diào)用Dispose(),使用using時,它是默認調(diào)用Dispose()方法。所以使用using的類也要繼承IDisposable接口。
Dispose()方法比較靈活,在資源不需要時立即釋放。它是資源的最終處理,調(diào)用它意味著會最終刪除對象。
三、Close()方法,暫時處置資源的狀態(tài),可能以后還會使用。一般處理非托管資源。
public viod Close()
//對非托管資源狀態(tài)的設置,如關閉文件或數(shù)據(jù)庫連接
對非托管資源狀態(tài)的設置,一般是關閉文件或數(shù)據(jù)庫連接。
下面寫一個綜合且又經(jīng)典的的例子,利用代碼演示一下各部分的作用:(為了省事,這個例子是從網(wǎng)上杜撰來的,只要說明問題就可以了,你說呢。在此應該感謝代碼原創(chuàng)者,感謝他寫了這么經(jīng)典和易懂的代碼,我們受益匪淺!)
public class ResourceHolder : System.IDisposable
Dispose(true);
System.GC.SuppressFinalize(this);
// 上面一行代碼作用是防止"垃圾回收器"調(diào)用這個類中的析構(gòu)方法
// 為什么要防止呢? 因為如果用戶記得調(diào)用Dispose()方法,那么
// 如果用戶不記得調(diào)用呢,就讓"垃圾回收器"幫我們?nèi)?多此一舉"吧 ^_^
// 你看不懂我上面說的不要緊,下面我還有更詳細的解釋呢!
protected virtual void Dispose(bool disposing)
if (disposing)
// 這里是清理"托管資源"的用戶代碼段。
// 這里是清理"非托管資源"的用戶代碼段。此處為析構(gòu)方法的實際執(zhí)行代碼,為了避免客戶代碼忘記顯示調(diào)用Dispose()方法,所作的備份。
~ResourceHolder()
Dispose(false); // 這里是清理"非托管資源"
如果看不明白以上代碼,一定要仔細閱讀以下解釋,很經(jīng)典,不看會后悔呦。
這里,我們必須要清楚,需要用戶調(diào)用的是方法Dispose()而不是方法Dispose(bool),然而,這里真正執(zhí)行釋放工作的方法卻并不是Dispose(),而是Dispose(bool) ! 為什么呢?仔細看代碼,在Dispose()中,調(diào)用了Dispose(true),而參數(shù)為"true"時,作用是清理所有的托管資源和非托管資源;大家一定還記得我前面才說過,"使用析構(gòu)方法是用來釋放非托管資源的",那么這里既然Dispose()可以完成釋放非托管資源的工作,還要析構(gòu)方法干什么呢? 其實,析構(gòu)方法的作用僅僅是一個"備份"!
為什么呢?
來自: 昵稱10504424 > 《C#》
0條評論
發(fā)表
請遵守用戶 評論公約
.NET Framework 自動內(nèi)存管理機制深入剖析 (C#分析篇) - syinter...
NET Framework 自動內(nèi)存管理機制深入剖析 (C#分析篇) - syinter...* * public void Dispose() * * 該成員支持 .NET 框架結(jié)構(gòu),因此不適用于直接從代碼中使用。...
.NET基礎拾遺(1)類型語法基礎和內(nèi)存管理基礎
①當每個包含F(xiàn)inalize方法的類型的實例對象被分配時,.NET會在一張?zhí)囟ǖ谋斫Y(jié)構(gòu)中添加一個引用并且指向這個實例對象,暫且稱該表為“帶...
托管資源和非托管資源
托管資源和非托管資源。Dispose()的執(zhí)行代碼顯式釋放由對象直接使用的所有未托管資源,并在所有實現(xiàn)IDisposable接口的封裝對象上調(diào)用Dispose()。傳遞給Dispose(bool)的參數(shù)表示Dispose(bool)是由析構(gòu)函...
常用的.NET面試問題 - 1
答:托管代碼是由CLR而不是操作系統(tǒng)執(zhí)行的代碼,編譯器首先將托管代碼編譯為中間語言代碼。另一方面,非托管代碼是在CLR環(huán)境或操作系統(tǒng)...
C# vs C++之二:GC vs RAII
GC在回收無用對象資源時,可以自動回收托管資源(比如托管內(nèi)存),但對于非托管資源(比如Socket、文件、數(shù)據(jù)庫連接)必須在程序中顯式釋放。Finalizer是對象被GC回收之前調(diào)用的終結(jié)器,初衷是在這里釋...
托管代碼和非托管代碼有什么區(qū)別?
托管代碼和非托管代碼有什么區(qū)別? 托管和非托管是修飾內(nèi)存的。實際上只是堆上的內(nèi)存管理,棧內(nèi)存和以前的一樣,函數(shù)退出則釋放,heap上的內(nèi)存,非托管內(nèi)存需要自己分配,調(diào)用構(gòu)造函數(shù)(c需要,c...
c#托管資源和非托管資源區(qū)別
c#托管資源和非托管資源區(qū)別在了解Finalize和Dispose之前,我們需要了解兩個概念,一個是托管資源,一個非委托資源。其中托管資源一般是指被CLR控制的內(nèi)存資源,這些資源的管理可以由CLR來控制,例如程...
.net垃圾回收機制詳解
.net垃圾回收機制詳解1. 自動內(nèi)存管理和GC 在原始程序中堆的內(nèi)存分配是這樣的:找到第一個有足夠空間的內(nèi)存地址(沒被占用的),然后將該內(nèi)存分配。2. GC工作方式 首先我們要知道托管代碼中的對...
GC回收機制
GC回收機制GC回收機制。我說了GC是隨機的,哪么你只管點你的,不一會GC就會來回收的(這里我們可以認為,內(nèi)存中存在一定數(shù)量的垃圾之后,GC會來),要證明GC來過我們把AA類改成 public class AA.dispos...
微信掃碼,在手機上查看選中內(nèi)容