C 的資料型別以及記憶體管理機制剖析(2)

2022-03-26 18:06:29 字數 3354 閱讀 4230

1. object類再分析:

system.object是所有.net類的基類,包括值型別和引用型別。值型別為什麼也是繼承於system.object的呢?object不是引用型別嗎?這個就涉及了.net的乙個有趣而神奇的機制--裝箱和拆箱(box&un-box)。這個後面會提到。

object是所有類(class)和結構(struct)的基類。class都是繼承於object類的,struct都是繼承於system.valuetype的,而system.valuetype是繼承object。

好了,既然object類級別這麼高,那麼它應該包含哪些成員呢?當然是不會有成員變數了,這東西不可以在那麼高階的類裡存在的,而且也沒有必要。不過object類定義了很多通用的方法,如果你新建的類沒有過載這些方法,那你的新建類就會自動繼承object類的這些方法。我把這些通用方法列於下表,以便大家參考:

方法名字首修飾符

作用string tostring()

public virtual

返回物件的字串表示

int gethashtable()

public virtual

在實現字典(雜湊表)時使用

這是在集合(雜湊表中)使用的物件

bool equals(object obj)

public virtual

對物件的例項進行相等比較

bool equals(object obj1, object obj2)

public static

對物件的例項進行相等比較

bool referenceequals(object obj1, object obj2)

public static

比較兩個引用是否指向同乙個物件

type gettype()

public

返回物件型別的詳細資訊

object memberwiseclone()

protected

進行物件的淺表複製

void finalize()

protected virtual

析構函式

在上面我們看到了一些像virtual,static,protected這樣的修飾符,我在學習c#語言機制的時候曾經對這些內容做了些詳細的整理,請參考《c#修飾符大總結》。

我們看virtual修飾符,這說明某些方法是能夠被過載的。比如說tostring()這樣的方法。我們自己所定義的類不特別宣告的話,都會繼承object。也就是說object的這些公用方法存在於每乙個類中,無論是.net framework中的類還是自定義的類。

2. 垃圾**機制,dispose() & finalize()

在《c#的資料型別以及記憶體管理機制剖析(1)》中我提到了.net的垃圾**機制。這裡在簡要地提一下,這個機制真的是.net核心內容之一,儘管不能夠被直接使用,但理解其機制卻相當重要。能夠在程式中避免很多不必要的錯誤。gc的流程如下圖所示:

我們可以在程式中呼叫垃圾**:

system.gc.collect()
不過請大家小心,並不是呼叫了這段**後,垃圾**就能夠**所有未引用物件。這個也是要分情況的,有時候釋放了集合物件,但是集合中的元素並不一定會被釋放。這還要看這個元素物件是否也出了**作用域(**中表示就是,離開包含該元素的某一層括號)。垃圾**機制能夠很好得管理託管資源和記憶體,但是在處理一些非託管資源比如檔案控制代碼、網路連線、資料庫、特殊裝置等,就會有一些問題。

(1).net析構函式finalize()

class testclass

}

事實上這個析構函式會在生成il時被編譯成下面的形式,會自動得生成finalize方法:

protescted overide void finalize() 

finally

}

析構函式會在gc釋放物件之前呼叫,由於.net垃圾**的機制,我們無法控制析構函式的執行的時間,也無法預知析構函式。所以如果我們需要去釋放非託管資源,把這個釋放的操作放在析構函式finalize()中會遇到麻煩。主要有幾個原因:①我們無法控制析構函式在特定的時候來執行,這樣有些重要資源使用完就應該立刻釋放的,就不適合放置這裡。②也不可能控制finalize的執行順序,但某些物件有關聯,需要順序釋放的情況也是不能完成的。③析構函式執行,會延遲該物件記憶體釋放的時間。必須要等到第二次gc才有可能完全釋放改物件。④執行庫用乙個執行緒順序鏈式得執行每個需要執行的finalize方法,這個佇列會影響效能。

綜上所述,finalize()是不適合在.net程式中對乙個物件的資源釋放和最後處理,同時對執行時間有要求的一些操作。c#推薦使用system.idisposable來取代這個析構函式。加入finalize後的gc機制如圖所示:

(2)idisposable介面

idisposable提供了可以在確定的時機釋放未託管資源的功能。其避免了析構函式以為垃圾收集機制而產生的一些問題。在物件結束的時候顯式得呼叫dispose()方法可以直接做一些釋放資源的操作。

class testclass:idisposable

}

上面是實現idisposable這個介面,我們為了使乙個物件總是能執行dispose方法,通常我們會把dispose()放在try/catch的final段,也就是無論怎樣都一定會執行,包括異常情況。假設我們有乙個criticalresource類,那麼可以這麼做:

criticalresource instance = null;

tryfinally

//也可以用下面的方式,使用using塊,可以減少**量,起到同樣效果

using(criticalresource instance = new criticalresource)

(3)finalize和dispose的雙重實現可以將dispose()作為結束物件的方法,finalize做為安全機制(沒有呼叫dispose是作為保險的方式)。這個方式應該是最佳釋放資源解決方案,不過比較複雜些,可以參考下面的簡單實現。

public class cresource : idisposable

protected virtual void dispose(bool disp)

//釋放非託管資源

}isdisposed = true;

}~cresource()

public testmethod()}}

變數的含義,記憶體管理機制,資料型別的含義

目錄互動式 進入python直譯器中一行行執行。直譯器 檔名的形式 例如 python test.py 記錄世間萬物的一種變化的一種狀態,稱為變數 在python中變數由哪些部分組成 變數名 變數名是用來引用變數值,但凡需要用到變數值,都需要通過變數名來定義 賦值符號 賦值 變數值 存放資料。用來記...

c 回顧 記憶體管理機制

在這個模型中,我們將會把乙個 c 程式在執行的時候所佔據的記憶體空間,分成以下四個部分 在 c 程式的記憶體空間中,我們在 中宣告的區域性變數,以及函式的形式引數,都儲存在棧區中 這部分內存在程式執行的時候會自動分配,而在不需要的時候也會自動釋放,並不需要程式設計師自己去手動維護。而我們使用new運...

Linux的記憶體管理機制

記憶體管理的一些基本概念 位址記憶體管理主要解決以下問題 程序的位址空間隔離 提高記憶體的使用效率 程式執行時重定位問題 現在的記憶體管理方法就是在程式和物理記憶體之間引入了虛擬記憶體這個概念。虛擬記憶體位於程式和物理記憶體之間,程式只能看到虛擬記憶體,再也不能直接訪問物理記憶體。每個程序都有自己的...