<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      摘要 : 最近在博客園里面看到有人在討論 C# String的一些特性. 大部分情況下是從CODING的角度來(lái)討論String. 本人覺(jué)得非常好奇, 在運(yùn)行時(shí)態(tài), String是如何與這些特性聯(lián)系上的. 本文將側(cè)重在通過(guò)WinDBG來(lái)觀察String在進(jìn)程內(nèi)的布局, 以此來(lái)解釋C# String的一些特性.

       

      問(wèn)題

      C# String有兩個(gè)比較有趣的特性.

      1. String的恒定性. 字符串橫定性是指一個(gè)字符串一經(jīng)創(chuàng)建,就不可改變。那么也就是說(shuō)當(dāng)我們改變string值的時(shí)候,便會(huì)在托管堆上重新分配一塊新的內(nèi)存空間,而不會(huì)影響到原有的內(nèi)存地址上所存儲(chǔ)的值。
      2. String的駐留. CLR runtime通過(guò)維護(hù)一個(gè)表來(lái)存放字符串,該表稱為拘留池,它包含程序中以編程方式聲明或創(chuàng)建的每個(gè)唯一的字符串的一個(gè)引用。因此,具有特定值的字符串的實(shí)例在系統(tǒng)中只有一個(gè)。

      對(duì)應(yīng)著兩個(gè)特性, 我產(chǎn)生了一些疑問(wèn).

      • String的恒定性是怎么樣讓string進(jìn)行比較的時(shí)候出現(xiàn)有趣的結(jié)果的? 它的比較結(jié)果為什么會(huì)與其他引用類型的結(jié)果不一樣?
      • 什么樣的String會(huì)被放到拘留池中?
      • 拘留池是怎樣的數(shù)據(jù)結(jié)構(gòu)? 它真是個(gè)Hashtable嗎?
      • 駐留在拘留池內(nèi)的String會(huì)不會(huì)被GC,  它的生命周期會(huì)有多長(zhǎng)(什么時(shí)候才會(huì)被回收)?

       

      String的恒定性

      先看一下下面的例子 :

       

      private static void Comparation()
      {
          string a = "Test String";
          string b = "Test String";
          string c = a;
      
          Console.WriteLine("a vs b : " + object.ReferenceEquals(a, b));
          Console.WriteLine("a vs c : " + object.ReferenceEquals(a, c));
      
          SimpleObject smp1 = new SimpleObject(a);
          SimpleObject smp2 = new SimpleObject(a);
      
          Console.WriteLine("smp1 vs smp2 : " + object.ReferenceEquals(smp1, smp2));
          Console.ReadLine();
      
      }
      
      class SimpleObject
      {
          public string name = string.Empty;
      
          public SimpleObject(string name)
          {
              this.name = name;
          }
      }


       

      image

      從結(jié)果上看, 雖然是不同的變量 a, b, c. 由于字符串的內(nèi)容是相同的, 所以比較的結(jié)果也是完全相同的. 對(duì)比SimpleObject的實(shí)例, smp1和smp2的值雖然也是相同的,但是比較的結(jié)果為false.

      下面看一下運(yùn)行時(shí), 這些objects的的情況.

      在運(yùn)行時(shí)態(tài), 一切皆是地址. 判斷兩個(gè)變量是否是相同的對(duì)象, 直觀的可以從它地址是否是相同的地址來(lái)進(jìn)行判斷.

      用dso命令打印出棧上對(duì)應(yīng)的Objects. 可以看到Test String”雖然出現(xiàn)了3次, 但是他們都對(duì)應(yīng)了一個(gè)地址0000000002473f90 . SimpleObject的對(duì)象實(shí)例出現(xiàn)了2次, 而且地址不一樣, 分別是00000000024776700000000002477688 .

      所以, 在使用String的時(shí)候, 實(shí)質(zhì)上是重用了相同的String 對(duì)象. 在new一個(gè)SimpleObject的實(shí)例時(shí)候, 每一次new都會(huì)在新的地址上初始化該對(duì)象的結(jié)構(gòu). 每次都是一個(gè)新的對(duì)象.

       

       

      0:000> !dso
      OS Thread Id: 0x3f0c (0)
      RSP/REG          Object           Name
      ......
      
      000000000043e730 0000000002473f90 System.String
      000000000043e738 0000000002473f90 System.String
      000000000043e740 0000000002473f90 System.String
      000000000043e748 0000000002477670 ConsoleApplication3.SimpleObject
      000000000043e750 0000000002477688 ConsoleApplication3.SimpleObject
      .......
      
      0:000> !do 0000000002473f90 
      Name: System.String
      MethodTable: 00007ffdb0817df0
      EEClass: 00007ffdb041e560
      Size: 48(0x30) bytes
      GC Generation: 0
      (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
      String: Test String
      Fields:
                    MT            Field           Offset                 Type VT             Attr            Value Name
      00007ffdb081f060  4000096        8         System.Int32  1 instance               12 m_arrayLength
      00007ffdb081f060  4000097        c         System.Int32  1 instance               11 m_stringLength
      00007ffdb0819838  4000098       10          System.Char  1 instance               54 m_firstChar
      00007ffdb0817df0  4000099       20        System.String  0   shared           static Empty
                                       >> Domain:Value  0000000000581880:0000000002471308 <<
      00007ffdb08196e8  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                       >> Domain:Value  0000000000581880:0000000002471be0 <<
      

       

      當(dāng)字符串內(nèi)容發(fā)生改變的時(shí)候, 任何微小的變化都會(huì)重新創(chuàng)建出一個(gè)新的String對(duì)象. 在我們調(diào)用這段代碼的時(shí)候

          Console.WriteLine("a vs b : " + object.ReferenceEquals(a, b));

      CLR runtime實(shí)際上做了兩件事情. 為字符"a vs b"分配了到了一個(gè)新的地址. 將對(duì)比結(jié)果與剛才的字符拼接到了一起, 分配到了另外一個(gè)新的地址. 如果多次拼接字符串, 就會(huì)分配到更多的新地址上, 從而可能會(huì)快速的占用大量的虛擬內(nèi)存. 這就是為什么微軟建議在這種情況下使用StringBuilder的原因.

       

      0:000> !dso
      
      Listing objects from: 0000000000435000 to 0000000000440000 from thread: 0 [3f0c]
      
      Address          Method Table    Heap Gen      Size Type
      …..
      0000000002473fc0 00007ffdb0817df0   0  0         44 System.String a vs b : 
      0000000002474138 00007ffdb0817df0   0  0         52 System.String a vs b : True
      
      …..
      

       

      String的駐留

      CLR runtime通過(guò)維護(hù)一個(gè)表來(lái)存放字符串,該表稱為拘留池,它包含程序中以編程方式聲明或創(chuàng)建的每個(gè)唯一的字符串的一個(gè)引用。因此,具有特定值的字符串的實(shí)例在系統(tǒng)中只有一個(gè)。 我們看一下如何來(lái)理解這句話.

      下面是示例代碼 :

       

      static void Main(string[] args)
      {
          int i = 0;
          while (true)
          {
              SimpleString(i++);
      
              Console.WriteLine( i + " : Run GC.Collect()");
              GC.Collect();
              Console.ReadLine();
          }
      }
      
      private static void SimpleString(int i)
      {
          string s = "SimpleString method ";
          string c = "Concat String";
      
          Console.WriteLine(s + c);
          Console.WriteLine(s + i.ToString());
          Console.ReadLine();
      }

       

      這是第一次的執(zhí)行結(jié)果. 此時(shí)只執(zhí)行到了SimpleString里面, 還沒(méi)有從這個(gè)方法返回.

      image

      我們可以看到stack上有4個(gè)string. 分別是按照代碼邏輯拼接起來(lái)的string的內(nèi)容. 從這里我們就可以當(dāng)我們?cè)谄唇幼址臅r(shí)候, 實(shí)際上會(huì)在Heap上創(chuàng)建出多個(gè)String的對(duì)象, 以此來(lái)完成這個(gè)拼接動(dòng)作.

      0:000> !dso
      
      Listing objects from: 0000000000386000 to 0000000000390000 from thread: 0 [3f50]
      
      …..
      0000000002a93f70 00007ffdb0817df0   0  0         66 System.String SimpleString method 
      0000000002a93fb8 00007ffdb0817df0   0  0         52 System.String Concat String
      0000000002a93ff0 00007ffdb0817df0   0  0         92 System.String SimpleString method Concat String
      0000000002a97a90 00007ffdb0817df0   0  0         28 System.String 0
      0000000002a97ab0 00007ffdb0817df0   0  0         68 System.String SimpleString method 0
      
      ……

       

      隨意用其中一個(gè)來(lái)檢查它的引用情況.

      從!gcroot的結(jié)果看, 這個(gè)string被兩個(gè)地方引用到. 一個(gè)是當(dāng)前的線程. 因?yàn)檎诒划?dāng)前線程使用到, 所以能夠看到這個(gè)非常正常.

      另外一個(gè)是root在一個(gè)System.Object[]數(shù)組上. 這個(gè)數(shù)組被PINNED在了App Domain 0000000000491880 上面. 這里顯示出來(lái), String其實(shí)是駐留在一個(gè)System.Object[]上面, 而不是很多人猜測(cè)的Hashtable. 不過(guò)料想CLR 應(yīng)該有一套機(jī)制可以從這個(gè)數(shù)組中快速的獲取正確的String. 不過(guò)這點(diǎn)不在本篇的討論范圍之內(nèi).

       

      0:000> !gcroot 0000000002a93f70
      Note: Roots found on stacks may be false positives. Run "!help gcroot" for
      more info.
      Scan Thread 0 OSTHread 81a0
      RSP:b9e9b8:Root:0000000002a93f70(System.String)
      Scan Thread 2 OSTHread 7370
      DOMAIN(0000000000C51880):HANDLE(Pinned):217e8:Root:0000000012a93030(System.Object[])->
      0000000002a93f70(System.String)

       

      我們可以檢查一下這個(gè)System.Object[]里面都有什么.

      從這個(gè)數(shù)組里面可以看到代碼中顯示聲明的的字符串. 第一個(gè)元素是一個(gè)空值, 這個(gè)里面保留的是我們最常用的String.Empty的實(shí)例. 第二個(gè)元素是”Run GC.Collect()”. 這個(gè)在code的里面的main函數(shù)中. 當(dāng)前還沒(méi)有被執(zhí)行到, 但是已經(jīng)被JITed到了該數(shù)組中. 其他兩個(gè)被顯示定義的字符串也能夠在這個(gè)數(shù)組中被找到. 另外可以確認(rèn)的是, 拼接出來(lái)的字符串, 臨時(shí)生成的字符串都沒(méi)有在這里出現(xiàn). 然而, 通過(guò)拼接出來(lái)的String并不在這個(gè)數(shù)組里面. 雖然拼接出來(lái)的String同樣分配到了heap上面, 但是不會(huì)被收納到數(shù)組中.

      0:000> !dumparray -details 0000000012a93030
      Name: System.Object[]
      MethodTable: 00007ffdb0805be0
      EEClass: 00007ffdb041eb88
      Size: 1056(0x420) bytes
      Array: Rank 1, Number of elements 128, Type CLASS
      Element Methodtable: 00007ffdb08176e0
      [0] 0000000002a91308
          Name: System.String
          MethodTable: 00007ffdb0817df0
          EEClass: 00007ffdb041e560
          Size: 26(0x1a) bytes
           (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
          String:         
          Fields:
                        MT    Field   Offset                 Type VT     Attr            Value Name
          00007ffdb081f060  4000096        8         System.Int32  1 instance                1 m_arrayLength
          00007ffdb081f060  4000097        c         System.Int32  1 instance                0 m_stringLength
          00007ffdb0819838  4000098       10          System.Char  1 instance                0 m_firstChar
          00007ffdb0817df0  4000099       20        System.String  0   shared           static Empty
                                       >> Domain:Value  0000000000c51880:0000000002a91308 <<
          00007ffdb08196e8  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                       >> Domain:Value  0000000000c51880:0000000002a91be0 <<
      [1] 0000000002a93f30
          Name: System.String
          MethodTable: 00007ffdb0817df0
          EEClass: 00007ffdb041e560
          Size: 64(0x40) bytes
           (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
          String:      : Run GC.Collect()    
          Fields:
                        MT    Field   Offset                 Type VT     Attr            Value Name
          00007ffdb081f060  4000096        8         System.Int32  1 instance               20 m_arrayLength
          00007ffdb081f060  4000097        c         System.Int32  1 instance               19 m_stringLength
          00007ffdb0819838  4000098       10          System.Char  1 instance               20 m_firstChar
          00007ffdb0817df0  4000099       20        System.String  0   shared           static Empty
                                       >> Domain:Value  0000000000c51880:0000000002a91308 <<
          00007ffdb08196e8  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                       >> Domain:Value  0000000000c51880:0000000002a91be0 <<
      [2] 0000000002a93f70
          Name: System.String
          MethodTable: 00007ffdb0817df0
          EEClass: 00007ffdb041e560
          Size: 66(0x42) bytes
           (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
          String:     SimpleString method     
          Fields:
                        MT    Field   Offset                 Type VT     Attr            Value Name
          00007ffdb081f060  4000096        8         System.Int32  1 instance               21 m_arrayLength
          00007ffdb081f060  4000097        c         System.Int32  1 instance               20 m_stringLength
          00007ffdb0819838  4000098       10          System.Char  1 instance               53 m_firstChar
          00007ffdb0817df0  4000099       20        System.String  0   shared           static Empty
                                       >> Domain:Value  0000000000c51880:0000000002a91308 <<
          00007ffdb08196e8  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                       >> Domain:Value  0000000000c51880:0000000002a91be0 <<
      [3] 0000000002a93fb8
          Name: System.String
          MethodTable: 00007ffdb0817df0
          EEClass: 00007ffdb041e560
          Size: 52(0x34) bytes
           (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
          String:     Concat String    
          Fields:
                        MT    Field   Offset                 Type VT     Attr            Value Name
          00007ffdb081f060  4000096        8         System.Int32  1 instance               14 m_arrayLength
          00007ffdb081f060  4000097        c         System.Int32  1 instance               13 m_stringLength
          00007ffdb0819838  4000098       10          System.Char  1 instance               43 m_firstChar
          00007ffdb0817df0  4000099       20        System.String  0   shared           static Empty
                                       >> Domain:Value  0000000000c51880:0000000002a91308 <<
          00007ffdb08196e8  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                       >> Domain:Value  0000000000c51880:0000000002a91be0 <<
      

       

      繼續(xù)讓代碼執(zhí)行下去, 我們需要來(lái)幾次GC. 驗(yàn)證一下駐留的字符串是否會(huì)在不使用之后被GC掉.

      GC完成之后, 按照所設(shè)想的, CallStack上面的String都已經(jīng)被清除掉了.同時(shí)因?yàn)橐呀?jīng)做過(guò)了GC動(dòng)作, GC heap進(jìn)過(guò)了壓縮, 沒(méi)有被PINNED住的對(duì)象地址會(huì)發(fā)生改變. 所以要驗(yàn)證駐留的String是否會(huì)被回收, 可以從駐留數(shù)組下手. 由于該數(shù)組是被PINNED住, 所以即使發(fā)生了GC的動(dòng)作, 它的地址也不會(huì)發(fā)生改變. 所以可以通過(guò)相同的命令把數(shù)組里面駐留的String都列出來(lái).

      結(jié)果是與我的預(yù)期是一致的. 只有被顯示定義的String保留在該數(shù)組內(nèi), 而這些String不會(huì)被回收. 通過(guò)拼接零時(shí)生產(chǎn)的String, 則不會(huì)加入到這個(gè)數(shù)組內(nèi), 在GC發(fā)生后, 由于沒(méi)有被引用而被回收掉.

       

      0:000> !dumparray -details 0000000012a93030
      Name: System.Object[]
      MethodTable: 00007ffdb0805be0
      EEClass: 00007ffdb041eb88
      Size: 1056(0x420) bytes
      Array: Rank 1, Number of elements 128, Type CLASS
      Element Methodtable: 00007ffdb08176e0
      [0] 0000000002a91308
          Name: System.String
          MethodTable: 00007ffdb0817df0
          EEClass: 00007ffdb041e560
          Size: 26(0x1a) bytes
           (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
          String:         
      ...
      [1] 0000000002a93f30
          Name: System.String
          MethodTable: 00007ffdb0817df0
          EEClass: 00007ffdb041e560
          Size: 64(0x40) bytes
           (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
          String:      : Run GC.Collect()    
      
      …
      [2] 0000000002a93f70
          Name: System.String
          MethodTable: 00007ffdb0817df0
          EEClass: 00007ffdb041e560
          Size: 66(0x42) bytes
           (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
          String:     SimpleString method     
          ...
      [3] 0000000002a93fb8
          Name: System.String
          MethodTable: 00007ffdb0817df0
          EEClass: 00007ffdb041e560
          Size: 52(0x34) bytes
           (C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
          String:     Concat String 

       

       

      所以經(jīng)過(guò)上面的觀察, 可以得出的結(jié)論是駐留的String生命周期非常長(zhǎng). 那么, 在什么時(shí)候他才會(huì)被回收?

      從上面gcroot的結(jié)果, 可以看到主流數(shù)組是被PINNED住. 而引用這個(gè)數(shù)組的App Domain 0000000000C51880.

      用!dumpdomain -stat的命令將所有的app domain信息打印出來(lái). 可以看到這個(gè)App Domain是我們代碼運(yùn)行的Domain (ConsoleApplication3.exe). 這個(gè)駐留數(shù)組是由CLR 來(lái)維護(hù), 并且與當(dāng)前的App Domain聯(lián)系到一起. 所以, 理論上這些駐留數(shù)組的生命周期跟這個(gè)App Domain是一致的.

       

      0:000> !dumpdomain -stat
      --------------------------------------
      System Domain: 00007ffdb1f16f60
      LowFrequencyHeap: 00007ffdb1f16fa8
      HighFrequencyHeap: 00007ffdb1f17038
      StubHeap: 00007ffdb1f170c8
      Stage: OPEN
      Name: None
      --------------------------------------
      Shared Domain: 00007ffdb1f17860
      LowFrequencyHeap: 00007ffdb1f178a8
      HighFrequencyHeap: 00007ffdb1f17938
      StubHeap: 00007ffdb1f179c8
      Stage: OPEN
      Name: None
      Assembly: 000000000047fa60
      --------------------------------------
      Domain 1: 0000000000491880
      LowFrequencyHeap: 00000000004918c8
      HighFrequencyHeap: 0000000000491958
      StubHeap: 00000000004919e8
      Stage: OPEN
      SecurityDescriptor: 0000000000494140
      Name: ConsoleApplication3.exe
      Assembly: 000000000047fa60 [C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]
      ClassLoader: 000000000047f820
      SecurityDescriptor: 000000000047f9a0
        Module Name
      00007ffdb03e1000 C:\windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
      

       

      寫(xiě)在最后面

      1. String的恒定性. 字符串橫定性是指一個(gè)字符串一經(jīng)創(chuàng)建,就不可改變。那么也就是說(shuō)當(dāng)我們改變string值的時(shí)候,便會(huì)在托管堆上重新分配一塊新的內(nèi)存空間,而不會(huì)影響到原有的內(nèi)存地址上所存儲(chǔ)的值。
      2. String的駐留. CLR runtime通過(guò)維護(hù)一個(gè)表來(lái)存放字符串,該表稱為拘留池,它包含程序中以編程方式聲明或創(chuàng)建的每個(gè)唯一的字符串的一個(gè)引用。因此,具有特定值的字符串的實(shí)例在系統(tǒng)(App Domain)中只有一個(gè)。
        直接在CODE里面聲明的String會(huì)被CLR runtime維護(hù)在一個(gè)Object[]內(nèi).
        臨時(shí)生成的string或者拼接出來(lái)的String不會(huì)維護(hù)在這個(gè)駐留數(shù)組中.
        駐留數(shù)組的生命周期跟它位于的App Domain一樣長(zhǎng). 所以GC并不會(huì)影響駐留數(shù)組所引用的String, 它們不會(huì)被GC.

      可以參考下面這個(gè)鏈接來(lái)對(duì)這兩個(gè)特性加深理解.

      http://blog.csdn.net/fengshi_sh/article/details/14837445

      http://www.rzrgm.cn/charles2008/archive/2009/04/12/1434115.html

      http://www.rzrgm.cn/instance/archive/2011/05/24/2056091.html

      posted on 2015-01-09 00:15  微軟互聯(lián)網(wǎng)開(kāi)發(fā)支持  閱讀(9095)  評(píng)論(25)    收藏  舉報(bào)
      主站蜘蛛池模板: 午夜色大片在线观看免费| 日韩高清视频 一区二区| 欧美成人VA免费大片视频| 看黄a大片日本真人视频直播| 中国女人内谢69xxxx| 国产女人18毛片水真多1| 久久精品蜜芽亚洲国产AV| 国模冰莲自慰肥美胞极品人体图| 亚洲久久色成人一二三区| 国产极品视频一区二区三区| 92国产福利午夜757小视频| 高潮潮喷奶水飞溅视频无码 | 亚洲国产成人无码电影| 动漫av网站免费观看| 99精品国产丝袜在线拍国语| 黑人玩弄人妻中文在线| 玩弄放荡人妻少妇系列| 国产成人亚洲日韩欧美| 成年无码av片完整版| 乱老年女人伦免费视频| 最新亚洲av日韩av二区| 免费人妻无码不卡中文18禁| 色综合激情丁香七月色综合 | 亚洲成a人片在线观看中| 久草热大美女黄色片免费看| 午夜在线不卡| 亚洲人成人网站色www| 免费一级黄色好看的国产| 乱码午夜-极品国产内射| 四虎成人在线观看免费| 欧美人与动牲猛交A欧美精品| 97人人添人人澡人人澡人人澡| 少妇高潮水多太爽了动态图| 精品精品亚洲高清a毛片| 卡一卡二卡三精品| 国产一区二区三区不卡视频| 国产成人高清亚洲一区二区| 国产成人精品18| 亚洲国产精品久久久久婷婷图片| 国产亚洲中文字幕久久网| 国产一区二区三区乱码在线观看 |