亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#字符串內(nèi)存駐留機(jī)制分析

 更新時(shí)間:2022年01月21日 11:48:19   作者:Artech  
這篇文章介紹了C#字符串內(nèi)存駐留機(jī)制,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

在這之前我寫過一些文章來(lái)介紹關(guān)于字符串內(nèi)存分配和駐留的文章,涉及到的觀點(diǎn)主要有:字符串的駐留機(jī)制避免了對(duì)具有相同字符序列的字符串對(duì)象的重復(fù)創(chuàng)建;被駐留的字符串是不受GC管轄的,即被駐留的字符串對(duì)象不能被GC回收;被駐留的字符串是被同一進(jìn)程中所有應(yīng)用程序域共享的。至于具體的原因,相信在《關(guān)于CLR內(nèi)存管理一些深層次的討論》中,你可以找到答案。由于這些天來(lái)在做一些關(guān)于內(nèi)存泄露審查的工作,所以想通過具體的Memory Profiling工具來(lái)為你證實(shí)上面的結(jié)論。我采用的Memory Profiling工具是Red Gate的ANTS Memory Profiler,陷于篇幅問題我不對(duì)該工具進(jìn)行詳細(xì)的介紹,有興趣的朋友可以登錄它的官網(wǎng)。

一、具有相同字符序列的String對(duì)象不會(huì)重復(fù)創(chuàng)建

首先來(lái)證明第一個(gè)結(jié)論:具有相同字符序列的String對(duì)象不會(huì)重復(fù)創(chuàng)建。我先創(chuàng)建了一個(gè)簡(jiǎn)單的Console應(yīng)用,編寫了如下的程序:在靜態(tài)方法BuildString中進(jìn)行了四次String對(duì)象的創(chuàng)建,str1和str2,str3和str4具有相同的值。該方法在Main方法中被執(zhí)行,在執(zhí)行前后通過調(diào)用Console.ReadLine方法讓程序Block住。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press any key to begin building string...");
        Console.ReadLine();
        BuildString();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }
 
    static void BuildString()
    {
        var str1 = "ABCDEFG";
        var str2 = "ABCDEFG";
        var str3 = "1234678";
        var str4 = "1234678";
    }
}

現(xiàn)在我們通過ANTS Memory Profiler啟動(dòng)代碼這個(gè)Console程序的exe文件,在靜態(tài)方法前后(也就是相應(yīng)的文字被輸出到控制臺(tái)的時(shí)候)拍攝兩個(gè)內(nèi)存快照。通過比較這兩個(gè)快照下對(duì)象的變化,我們發(fā)現(xiàn)多了3個(gè)String類型的實(shí)例。

圖1

我們進(jìn)一步追蹤著多出的3個(gè)字符串的值到底是多少,于是我們查看實(shí)例列表。從下面的截圖中我們可以清晰地看到:除了一個(gè)值為”byteIndex”的字符串之外,另兩個(gè)的值分別為”ABCDEFG”和“12345678”,它們就是我們?cè)陟o態(tài)方法BuildString創(chuàng)建的。在BuildString方法中,我們創(chuàng)建了4個(gè)String對(duì)象,而在這里我們我們只看到了兩個(gè)。這無(wú)疑證實(shí)了字符串駐留機(jī)制的存在。

圖2

二、字符串駐留機(jī)制同樣于string literal + string literal的運(yùn)算

“+”是我們最為常見的字符串操作符,當(dāng)我們通過該操作符對(duì)兩個(gè)字符串進(jìn)行連接操作的時(shí)候,字符串的駐留機(jī)制依然有效。為此,我將BuildString方式定義成如下的方式,采用相同的Profiling流程,你依然可以看到與圖2完全一樣的結(jié)果。

static void BuildString()
{
    var str1 = "ABCDEFG";
    var str2 = "ABCD" +"EFG";
    var str3 = "1234678";
    var str4 = "1234"+"678";
}

三、字符串駐留機(jī)智不適合Variable + string literal形式

雖然字符串的駐留適用于兩個(gè)通過引號(hào)括起來(lái)的字符串值直接進(jìn)行相加,但是如果將任何一個(gè)或者兩個(gè)換成字符串變量,最終運(yùn)算的結(jié)果是不能被駐留的。我們同樣可以通過類似于上面的步驟來(lái)證實(shí)這一點(diǎn),為此我們BuildString方法進(jìn)行了如下的修改。采用上面的Profiling流程,你看到的依然是圖2完全一樣的結(jié)果,也就是說無(wú)論是變量和一個(gè)字符串常量相加,還是兩個(gè)字符串常量相加,運(yùn)算的結(jié)果“ABCDEFG1234678”并沒有被駐留下來(lái)(實(shí)際上此時(shí)它已經(jīng)是一個(gè)垃圾對(duì)象,GC可以對(duì)其進(jìn)行回收)。

static void BuildString()
{
    var str1 = "ABCDEFG";
    var str2 = "1234678";
    var str3 = "ABCDEFG" + str2;
    var str4 = str1 + "1234678";
    var str5 = str1 + str2;
}

四、調(diào)用string.Intern可以對(duì)運(yùn)算結(jié)果進(jìn)行強(qiáng)制駐留

雖然涉及到變量的字符串連接運(yùn)算結(jié)果不會(huì)被駐留,但是我們可以通過調(diào)用string.Intern方法對(duì)其進(jìn)行強(qiáng)制駐留,該方法會(huì)迫使傳入傳入?yún)?shù)表示的字符串被保存到駐留池中。為此,我們對(duì)BuildString方法進(jìn)行如下的修改:將"ABCDEFG" + str2運(yùn)算的結(jié)構(gòu)傳入string.Intern靜態(tài)方法中。

static void BuildString()
{
    var str1 = "ABCDEFG";
    var str2 = "1234678";
    var str3 = string.Intern("ABCDEFG" + str2);
}

通過采用上面的Profiling流程,在新創(chuàng)建對(duì)象(New Object)String實(shí)例列表中,多出了一個(gè)“ABCDEFG1234678”。

圖3

五、駐留的字符串不能被GC回收

雖然String是一個(gè)引用類型,但是它卻不受GC管轄。GC在進(jìn)行回收的時(shí)候,看似垃圾對(duì)象的字符串實(shí)例依然保存在內(nèi)存中。為了演示,我們將BuildString方法還原成原來(lái)的代碼,并在調(diào)用該方法之后調(diào)用GC.Collect方法進(jìn)行強(qiáng)制垃圾回收。采用上面的Profiling流程,你看到的依然是圖2完全一樣的結(jié)果,四個(gè)本應(yīng)該是垃圾對(duì)象(str1~str4)在GC回收之后依然存在。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press any key to begin building string...");
        Console.ReadLine();
        BuildString();
        GC.Collect();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }
 
    static void BuildString()
    {
        var str1 = "ABCDEFG";
        var str2 = "ABCDEFG";
        var str3 = "1234678";
        var str4 = "1234678";
    }
}

六、字符串駐留是基于整個(gè)進(jìn)程的

現(xiàn)在來(lái)證明最后一個(gè)結(jié)論:駐留的字符串是基于整個(gè)進(jìn)程范圍的,而不是基于當(dāng)前AppDomain。為了證明這個(gè)結(jié)論,我們可以要寫多一點(diǎn)代碼。我們借用《關(guān)于CLR內(nèi)存管理一些深層次的討論》中的方式,創(chuàng)建了如下一個(gè)AppDomainContext類,該類是對(duì)一個(gè)AppDomain對(duì)象的封裝。Invoke方法實(shí)現(xiàn)了在一個(gè)單獨(dú)的AppDomain中執(zhí)行某個(gè)基于泛型類型實(shí)例的操作。

public class AppDomainContext
{
    public AppDomain AppDomain { get; private set; }
    private AppDomainContext(string friendlyName)
    {
        this.AppDomain = AppDomain.CreateDomain(friendlyName);
    }
    public static AppDomainContext CreateDomainContext(string friendlyName)
    {
        return new AppDomainContext(friendlyName);
    }
    public void Invoke<T>(Action<T> action)
    {
        T instance = (T)this.AppDomain.CreateInstanceAndUnwrap(typeof(T).Assembly.FullName, typeof(T).FullName);
        action(instance);
    }
}

然后我們將上述的BuildString方法實(shí)現(xiàn)在一個(gè)繼承自MarshalByRefObject的Foo類型中。

public class Foo : MarshalByRefObject
{
    public void BuildString()
    {
        var str1 = "ABCDEFG";
        var str2 = "ABCDEFG";
        var str3 = "1234678";
        var str4 = "1234678";
    }
}

然后再M(fèi)ain方法中,我們執(zhí)行如下的程序。下面的程序模擬的是創(chuàng)建了3個(gè)AppDomain,并在它們內(nèi)部進(jìn)行BuildString方法的執(zhí)行。如果字符串的駐留是基于AppDomain的話,應(yīng)該有6個(gè)String實(shí)例存在。但是采用上面的Profiling流程,你看到的依然圖2完全一樣的結(jié)果,這就充分證明了駐留機(jī)制是基于進(jìn)程而非AppDomain的結(jié)論。

static void Main(string[] args)
{
    Console.WriteLine("Press any key to begin building string...");
    Console.ReadLine();
    AppDomainContext.CreateDomainContext("Domain A").Invoke<Foo>(foo => foo.BuildString());
    AppDomainContext.CreateDomainContext("Domain B").Invoke<Foo>(foo => foo.BuildString());
    AppDomainContext.CreateDomainContext("Domain C").Invoke<Foo>(foo => foo.BuildString());
    GC.Collect();
    Console.WriteLine("Press any key to exit...");
    Console.ReadLine();
}

到此這篇關(guān)于C#字符串內(nèi)存駐留機(jī)制分析的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論