最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談C#中的string駐留池

 更新時(shí)間:2020年06月24日 14:24:07   作者:一線碼農(nóng)  
這篇文章主要介紹了C#中的string駐留池的的相關(guān)資料,文中示例代碼非常細(xì)致,供大家參考和學(xué)習(xí),感興趣的朋友可以了解下

昨天看群里在討論C#中的string駐留池,炒的火熱,幾輪下來理論一堆堆,但是在證據(jù)提供上都比較尷尬。雖然這東西很基礎(chǔ),但比較好的回答也不是那么容易,這篇我就以我能力范圍之內(nèi)跟大家分享一下

一:無處不在的池

開發(fā)這么多年,相信大家對(duì)‘池' 這個(gè)概念都耳熟能詳了,連接池,線程池,對(duì)象池,還有這里的駐留池,池的存在就是為了復(fù)用為了共享,獨(dú)樂樂不如眾樂樂,畢竟一個(gè)字符串的生成和銷毀既浪費(fèi)空間又浪費(fèi)時(shí)間,還不如先養(yǎng)著。

1. 說說現(xiàn)象

通常我們臆想中是這么認(rèn)為的,定義幾個(gè)字符串變量,堆上就會(huì)分配幾個(gè)string對(duì)象,其實(shí)這底層有一種叫駐留池技術(shù)可以做到如果兩個(gè)字符串內(nèi)容相同,那就在堆上只分配一個(gè)string對(duì)象,然后將引用地址分配給兩個(gè)字符串變量,這樣就可以大大降低了內(nèi)存使用,如果用代碼表示就是下面這樣。

    public static void Main(string[] args)
    {
      var str1 = "nihao";
      var str2 = "nihao";

      var b = string.ReferenceEquals(str1, str2);
      Console.WriteLine(b);
    }

----------- output -----------
True

2. 實(shí)現(xiàn)原理

那怎么做到的呢? 其實(shí)CLR在運(yùn)行時(shí)調(diào)用JIT把你的MSIL代碼轉(zhuǎn)成機(jī)器代碼的時(shí)候會(huì)發(fā)現(xiàn)你的元數(shù)據(jù)中定義了相同內(nèi)容的字符串對(duì)象,CLR就會(huì)把你的字符串放入它私有的的內(nèi)部字典中,其中key就是字符串內(nèi)容,value就是分配在堆上的字符串引用地址,這個(gè)字典就是所謂的駐留池,如果不是很明白,我來畫一張圖。

3. windbg驗(yàn)證

可以用windbg看一下棧中的str1和str2是否都指向了堆上對(duì)象的地址。

~0s -> !clrstack -l 在主線程的線程棧上找到變量str1和str2

0:000> ~0s
ntdll!ZwReadFile+0x14:
00007ff8`fea4aa64 c3       ret
0:000> !clrstack -l
OS Thread Id: 0x1c1c (0)
    Child SP        IP Call Site

000000ac0b7fed00 00007ff889e608e9 *** WARNING: Unable to verify checksum for ConsoleApp2.exe
ConsoleApp2.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp2\Program.cs @ 30]
  LOCALS:
    0x000000ac0b7fed38 = 0x0000024a21f22d48
    0x000000ac0b7fed30 = 0x0000024a21f22d48

000000ac0b7fef48 00007ff8e9396c93 [GCFrame: 000000ac0b7fef48] 

從上面代碼的 LOCALS 的 0x000000ac0b7fed38 = 0x0000024a21f22d48 0x000000ac0b7fed30 = 0x0000024a21f22d48可以看到兩個(gè)局部變量的引用地址都是 0x0000024a21f22d48,說明指向的都是一個(gè)堆對(duì)象,接下來再把堆上的內(nèi)容打出來。

0:000> !do 0x0000024a21f22d48
Name:    System.String
MethodTable: 00007ff8e7a959c0
EEClass:   00007ff8e7a72ec0
Size:    36(0x24) bytes
File:    C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:   nihao
Fields:
       MT  Field  Offset         Type VT   Attr      Value Name
00007ff8e7a985a0 4000281    8     System.Int32 1 instance        5 m_stringLength
00007ff8e7a96838 4000282    c     System.Char 1 instance        6e m_firstChar
00007ff8e7a959c0 4000286    d8    System.String 0  shared      static Empty
                 >> Domain:Value 0000024a203d41c0:NotInit <<

可以看到,果然是System.String對(duì)象,這就和我的圖是相符的。

二 駐留池的驗(yàn)證

1. String下的駐留池驗(yàn)證方法

很遺憾的是水平有限,由于駐留池既不在堆中也不在棧上,目前還不知道怎么用windbg去打印CLR中駐留池字典內(nèi)容,不過也可以通過 string.Intern 去驗(yàn)證。

    //
    // Summary:
    //   Retrieves the system's reference to the specified System.String.
    //
    // Parameters:
    //  str:
    //   A string to search for in the intern pool.
    //
    // Returns:
    //   The system's reference to str, if it is interned; otherwise, a new reference
    //   to a string with the value of str.
    //
    // Exceptions:
    //  T:System.ArgumentNullException:
    //   str is null.
    [SecuritySafeCritical]
    public static String Intern(String str);

從注釋中可以看到,這個(gè)方法的意思就是:如果你定義的str在駐留池中存在,那么就返回駐留池中命中內(nèi)容的堆上引用地址,如果不存在,將新字符串插入駐留池中再返回堆上引用,先上一下代碼:

    public static void Main(string[] args)
    {
      var str1 = "nihao";
      var str2 = "nihao";

      //驗(yàn)證nihao是否在駐留池中,如果存在那么str3 和 str1,str2一樣的引用
      var str3 = string.Intern("nihao");

      //驗(yàn)證新的字符串內(nèi)容是否進(jìn)入駐留池中
      var str4 = string.Intern("cnblogs");
      var str5 = string.Intern("cnblogs");

      Console.ReadLine();
    }

接下來分別驗(yàn)證一下str3是否也是和str1和str2一樣的引用,以及str5是否存在駐留池中。

ConsoleApp2.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp2\Program.cs @ 37]
  LOCALS:
    0x00000047105fea58 = 0x0000018537312d48
    0x00000047105fea50 = 0x0000018537312d48
    0x00000047105fea48 = 0x0000018537312d48
    0x00000047105fea40 = 0x0000018537312d70
    0x00000047105fea38 = 0x0000018537312d70

從五個(gè)變量地址中可以看到,nihao已經(jīng)被str1,str2,str3共享,cnblogs也進(jìn)入了駐留池中實(shí)現(xiàn)了共享。

2. 運(yùn)行期相同string是否進(jìn)入駐留池

這里面有一個(gè)坑,前面討論的相同字符串都是在編譯期就知道的,但運(yùn)行時(shí)中的相同字符串是否也會(huì)進(jìn)入駐留池呢? 這是一個(gè)讓人充滿好奇的話題,可以試一下,在程序運(yùn)行時(shí)接受IO輸入內(nèi)容hello,看看是否和str1,str2共享引用地址。

    public static void Main(string[] args)
    {
      var str1 = "nihao";
      var str2 = "nihao";

      var str3 = Console.ReadLine();

      Console.WriteLine("輸入完成!");
      Console.ReadLine();
    }

0:000> !clrstack -l
000000f6d35fee50 00007ff889e7090d *** WARNING: Unable to verify checksum for ConsoleApp2.exe
ConsoleApp2.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp2\Program.cs @ 33]
  LOCALS:
    0x000000f6d35fee98 = 0x000002cb1a552d48
    0x000000f6d35fee90 = 0x000002cb1a552d48
    0x000000f6d35fee88 = 0x000002cb1a555f28
0:000> !do 0x000002cb1a555f28
Name:    System.String
MethodTable: 00007ff8e7a959c0
EEClass:   00007ff8e7a72ec0
Size:    36(0x24) bytes
File:    C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:   nihao
Fields:
       MT  Field  Offset         Type VT   Attr      Value Name
00007ff8e7a985a0 4000281    8     System.Int32 1 instance        5 m_stringLength
00007ff8e7a96838 4000282    c     System.Char 1 instance        6e m_firstChar
00007ff8e7a959c0 4000286    d8    System.String 0  shared      static Empty
                >> Domain:Value 000002cb18ad39f0:NotInit <<

從上面內(nèi)容可以看到,從Console.ReadLine接收到的引用地址是 0x000002cb1a555f28 ,雖然是相同內(nèi)容,但卻沒有使用駐留池,這是因?yàn)轳v留池在JIT靜態(tài)解析期就已經(jīng)解析完成了,也就無法享受復(fù)用之優(yōu),如果還想復(fù)用的話,在 Console.ReadLine() 包一層string.Intern即可,如下所示:

    public static void Main(string[] args)
    {
      var str1 = "nihao";
      var str2 = "nihao";

      var str3 = string.Intern(Console.ReadLine());

      Console.WriteLine("輸入完成!");
      Console.ReadLine();
    }

ConsoleApp2.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp2\Program.cs @ 33]
  LOCALS:
    0x0000008fac1fe9c8 = 0x000001ff46582d48
    0x0000008fac1fe9c0 = 0x000001ff46582d48
    0x0000008fac1fe9b8 = 0x000001ff46582d48

可以看到這個(gè)時(shí)候str1,str2,str3共享一個(gè)內(nèi)存地址 0x000001ff46582d48。

四: 總結(jié)

駐留池技術(shù)是個(gè)很🐮👃的東西,很好的解決字符串在堆上的重復(fù)分配問題,大大減小了堆的內(nèi)存占用,但也要明白運(yùn)行期的IO輸入無法共享駐留池的解決方案。

好了,本篇就說到這里,希望對(duì)你有幫助!

以上就是淺談C#中的string駐留池的詳細(xì)內(nèi)容,更多關(guān)于C# string駐留池的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#異步綁定數(shù)據(jù)實(shí)現(xiàn)方法

    C#異步綁定數(shù)據(jù)實(shí)現(xiàn)方法

    這篇文章主要介紹了C#異步綁定數(shù)據(jù)實(shí)現(xiàn)方法,實(shí)例分析了C#操作數(shù)據(jù)庫及異步綁定的相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-09-09
  • .net與javascript腳本的交互方法總結(jié)

    .net與javascript腳本的交互方法總結(jié)

    這篇文章主要介紹了.net與javascript腳本的交互方法,實(shí)例講述了.net訪問javascript的方法與javascript訪問.net的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-10-10
  • C#實(shí)現(xiàn)折半查找算法

    C#實(shí)現(xiàn)折半查找算法

    這篇文章介紹了C#實(shí)現(xiàn)折半查找的算法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • C#獲取屬性的displayName的3種方式

    C#獲取屬性的displayName的3種方式

    在C#中,獲取屬性的displayName可以通過多種方式實(shí)現(xiàn),包括使用特性、反射和LINQ,下面我將分別展示每種方法,并提供具體的示例代碼,感興趣的朋友可以參考下
    2024-07-07
  • C# 使用Winform 獲取下拉框 選中的值

    C# 使用Winform 獲取下拉框 選中的值

    這篇文章主要介紹了C# 使用Winform 獲取下拉框 選中的值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 利用C#操作WMI指南

    利用C#操作WMI指南

    WMI提供了一套內(nèi)置在Microsoft Windows操作系統(tǒng)中的豐富的系統(tǒng)管理服務(wù),可以在有大量的應(yīng)用程序、服務(wù)和設(shè)備的系統(tǒng)中提供全方位的管理功能。它允許應(yīng)用程序的開發(fā)者,使用簡單的、一致的機(jī)制,去查詢企業(yè)中的任一臺(tái)計(jì)算機(jī)上的信息,或是進(jìn)行系統(tǒng)配置
    2016-11-11
  • Unity Shader模擬玻璃效果

    Unity Shader模擬玻璃效果

    這篇文章主要為大家詳細(xì)介紹了Unity Shader模擬玻璃效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • C# Record關(guān)鍵字示例詳解

    C# Record關(guān)鍵字示例詳解

    C#9.0引入record關(guān)鍵字,用于定義不可變且專注于數(shù)據(jù)表示的記錄類型,記錄類型自動(dòng)生成構(gòu)造函數(shù)、ToString、Equals和GetHashCode方法,并支持不可變性和可變性,適用于數(shù)據(jù)傳輸對(duì)象、不可變數(shù)據(jù)結(jié)構(gòu)和配置對(duì)象等場景,本文介紹C# Record關(guān)鍵字,感興趣的朋友一起看看吧
    2025-01-01
  • 基于C#實(shí)現(xiàn)圖像縮放與裁剪工具

    基于C#實(shí)現(xiàn)圖像縮放與裁剪工具

    圖像縮放與裁剪在多個(gè)領(lǐng)域和應(yīng)用場景中都非常常見,本文將介紹如何使用C#的GDI+(Graphics Device Interface)庫來實(shí)現(xiàn)一個(gè)圖像縮放與裁剪工具,有需要的可以參考下
    2025-03-03
  • C#實(shí)現(xiàn)縮放和剪裁圖片的方法示例

    C#實(shí)現(xiàn)縮放和剪裁圖片的方法示例

    這篇文章主要介紹了C#實(shí)現(xiàn)縮放和剪裁圖片的方法,結(jié)合實(shí)例形式分析了C#針對(duì)圖片屬性的縮放、裁剪等相關(guān)操作技巧,需要的朋友可以參考下
    2017-06-06

最新評(píng)論

绵阳市| 灵宝市| 大洼县| 英德市| 大丰市| 岳池县| 古丈县| 宁明县| 宕昌县| 永和县| 高台县| 景东| 宝应县| 虎林市| 盖州市| 宜昌市| 称多县| 邢台县| 河东区| 独山县| 龙南县| 门头沟区| 瓮安县| 大冶市| 贵定县| 苏州市| 吴旗县| 华蓥市| 昌图县| 绵竹市| 太康县| 会昌县| 阿克陶县| 镇远县| 盱眙县| 芦山县| 峨山| 长阳| 吉安市| 西安市| 巨鹿县|