|
一個(gè)月以前我寫了一篇討論字符串的駐留(string interning)的文章,我今天將會(huì)以字符串的駐留為基礎(chǔ),進(jìn)一步來(lái)討論.NET中的string。string interning的基本前提是string的恒定性(immutability),即string一旦被創(chuàng)建將不會(huì)改變。我們就先來(lái)談?wù)剆tring的恒定性。
一、string是恒定的(immutable)
和其他類型比較,string最為顯著的一個(gè)特點(diǎn)就是它具有恒定不變性:我們一旦創(chuàng)建了一個(gè)string,在managed heap 上為他分配了一塊連續(xù)的內(nèi)存空間,我們將不能以任何方式對(duì)這個(gè)string進(jìn)行修改使之變長(zhǎng)、變短、改變格式。所有對(duì)這個(gè)string進(jìn)行各項(xiàng)操作(比如調(diào)用ToUpper獲得大寫格式的string)而返回的string,實(shí)際上另一個(gè)重新創(chuàng)建的string,其本身并不會(huì)產(chǎn)生任何變化。
String的恒定性具有很多的好處,它首先保證了對(duì)于一個(gè)既定string的任意操作不會(huì)造成對(duì)其的改變,同時(shí)還意味著我們不用考慮操作string時(shí)候出現(xiàn)的線程同步的問(wèn)題。在string恒定的這些好處之中,我覺(jué)得最大的好處是:它成就了字符串的駐留。
CLR通過(guò)一個(gè)內(nèi)部的interning table保證了CLR只維護(hù)具有不同字符序列的string,任何具有相同字符序列的string所引用的均為同一個(gè)string對(duì)象,同一段為該string配分的內(nèi)存快。字符串的駐留極大地較低了程序執(zhí)行對(duì)內(nèi)存的占用。
對(duì)于string的恒定性和字符串的駐留,還有一點(diǎn)需要特別指出的是:string的恒定性不單單是針對(duì)某一個(gè)單獨(dú)的AppDomain,而是針對(duì)一個(gè)進(jìn)程的。
二、String可以跨AppDomain共享的(cross-appDomain)
我們知道,在一個(gè)托管的環(huán)境下,Appdomain是托管程序運(yùn)行的一個(gè)基本單元。AppDomain為托管程序提供了良好的隔離機(jī)制,保證在同一個(gè)進(jìn)程中的不同的Appdomain不可以共享相同的內(nèi)存空間。在一個(gè)Appdomain創(chuàng)建的對(duì)象不能被另一個(gè)Appdomain直接使用,對(duì)象在AppDomain之間傳遞需要有一個(gè)Marshaling的過(guò)程:對(duì)象需要通過(guò)by reference或者by value的方式從一個(gè)Appdomain傳遞到另一個(gè)Appdomain。具體內(nèi)容可以參照我的另一篇文章:用Coding證明Appdomain的隔離性。
但是這里有一個(gè)特例,那就是string。Appdomain的隔離機(jī)制是為了防止一個(gè)Application的對(duì)內(nèi)存空間的操作對(duì)另一個(gè)Application 內(nèi)存空間的破壞。通過(guò)前面的介紹,我們已經(jīng)知道了string是恒定不變的、是只讀的。所以它根本不需要Appdomain的隔離機(jī)制。所以讓一個(gè)恒定的、只讀的string被同處于一個(gè)進(jìn)程的各個(gè)Application共享是沒(méi)有任何問(wèn)題的。
String的這種跨AppDomain的恒定性成就了基于進(jìn)程的字符串駐留:一個(gè)進(jìn)程中各個(gè)Application使用的具有相同字符序列的string都是對(duì)同一段內(nèi)存的引用。我們將在下面通過(guò)一個(gè)Sample來(lái)證明這一點(diǎn)。
三、證明string垮AppDomain的恒定性
在寫這篇文章的時(shí)候,我對(duì)如何證明string跨AppDomain的interning,想了好幾天,直到我偶然地想到了為實(shí)現(xiàn)線程同步的lock機(jī)制。
我們知道在一個(gè)多線程的環(huán)境下,為了避免并發(fā)操作導(dǎo)致的數(shù)據(jù)的不一致性,我們需要對(duì)一個(gè)對(duì)象加鎖來(lái)阻止該對(duì)象被另一個(gè)線程 操作。相反地,為了證明兩個(gè)對(duì)象是否引用的同一個(gè)對(duì)象,我們只需要在兩個(gè)線程中分別對(duì)他們加鎖,如果程序執(zhí)行的效果和對(duì)同一個(gè)對(duì)象加鎖的情況完全一樣的話,那么就可以證明這兩個(gè)被加鎖的對(duì)象是同一個(gè)對(duì)象。基于這樣的原理我們來(lái)看看我們的Sample:















"Artech.ImmutableString", "Artech.ImmutableString.MarshalByRefType") as MarshalByRefType;

"Artech.ImmutableString", "Artech.ImmutableString.MarshalByRefType") as MarshalByRefType;





























NET技術(shù):深入理解string和如何高效地使用string,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。