日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.Net Discovery系列之十二-深入理解平台机制与性能影响(下)

發(fā)布時間:2025/3/18 asp.net 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .Net Discovery系列之十二-深入理解平台机制与性能影响(下) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? 上一篇文章中Aicken為大家介紹了.Net平臺的垃圾回收機制、即時編譯機制與其對性能的影響,這一篇中將繼續(xù)為大家介紹.Net平臺的異常捕獲機制與字符串駐留機制。

三.關(guān)于異常捕獲機制

??? 雖然我們已經(jīng)很辛苦了,但是仍然有很多原因使代碼運行失敗,如引用null引用、索引越界、內(nèi)存溢出、類型轉(zhuǎn)換失敗等等。這就需要我們的代碼有足夠的容錯能力,在代碼運行失敗時,及時、主動的處理這些異常。

● 機制分析

??? .Net 中基本的異常捕獲與處理機制是由try…catch…finally塊來完成的,它們分別完成了異常的監(jiān)測、捕獲與處理工作。一個try塊可以對應(yīng)零個或多個catch塊,可以對應(yīng)零個或一個finally塊。不過沒有catch的try似乎沒有什么意義,如果try對應(yīng)了多個catch,那么監(jiān)測到異常后,CLR會自上而下搜索catch塊的代碼,并通過異常過濾器篩選對應(yīng)的異常,如果沒有找到,那么CLR將沿著調(diào)用堆棧,向更高層搜索匹配的異常,如果已到堆棧頂部依然沒有找到對應(yīng)的異常,就會拋出未處理的異常了,這時catch塊中的代碼并不會被執(zhí)行。所以距離try最近的catch塊將最先被遍歷到。

  以下代碼:

  

代碼 try
{
Convert.ToInt32(
"Try");
}
catch (FormatException ex1)
{
string CatchFormatException = "CatchFormatException";
}
catch (NullReferenceException ex2)
{
string CatchNullReferenceException = "CatchNullReferenceException";
}
finally
{
string Finally = "Finally";
}

?

?

1 ??對應(yīng)IL如下:?
.method private hidebysig instance void? Form1_Load(object sender,
class [mscorlib]System.EventArgs e) cil managed
{
// Code size?????? 53 (0x35)
? .maxstack? 1
.locals init ([
0] class [mscorlib]System.FormatException ex1,
[
1] string CatchFormatException,
[
2] class [mscorlib]System.NullReferenceException ex2,
[
3] string CatchNullReferenceException,
[
4] string Finally)
IL_0000:? nop
IL_0001:? nop
IL_0002:? ldstr?????
"Try"
? IL_0007:? call?????? int32 [mscorlib]System.Convert::ToInt32(
string)
IL_000c:? pop
IL_000d:? nop
IL_000e:? leave.s??? IL_0026
IL_0010:? stloc.0

IL_0011:? nop
IL_0012:? ldstr?????
"CatchFormatException"
? IL_0017:? stloc.
1
? IL_0018:? nop
IL_0019:? leave.s??? IL_0026
IL_001b:? stloc.
2
IL_001c:? nop
IL_001d:? ldstr?????
"CatchNullReferenceException"
? IL_0022:? stloc.
3
? IL_0023:? nop
IL_0024:? leave.s??? IL_0026
? IL_0026:? nop
IL_0027:? leave.s??? IL_0033
IL_0029:? nop
IL_002a:? ldstr?????
"Finally"
? IL_002f:? stloc.s??? Finally
IL_0031:? nop
IL_0032:? endfinally
IL_0033:? nop
? IL_0034:? ret
IL_0035:?
// Exception count 3
? .try IL_0001 to IL_0010 catch [mscorlib]System.FormatException handler IL_0010 to IL_001b
.
try IL_0001 to IL_0010 catch
[mscorlib]System.NullReferenceException handler IL_001b to IL_0026
.
try IL_0001 to IL_0029 finally
handler IL_0029 to IL_0033
}
// end of method Form1::Form1_Load

??? 末尾的幾行代碼揭示出IL是怎樣處理異常處理的。最后三行的每一個Item被稱作Exception Handing Clause,EHC組成Exception Handing Table,EHT與正常代碼之間由ret返回指令隔開。

??? 可以看出,FormatException排列在EHT的第一位。

??? 當(dāng)代碼成功執(zhí)行或反之而返回后,CLR會遍歷EHT:

??????? 1. 如果拋出異常, CLR會根據(jù)拋出異常的代碼的“地址”找到對應(yīng)的EHC(IL_0001 to IL_0010為檢測代碼的范圍),這個例子中CLR將找到2條EHC,???? FormatException會最先被遍歷到,且為適合的EHC。

??????? 2. 如果返回的代碼地址在IL_0001 to IL_0029內(nèi),那么還會執(zhí)行finally handler?即IL_0029 to IL_0033中的代碼,不管是否因成功執(zhí)行代碼而返??????? 回。

??? 事實上,catch與finally的遍歷工作是分開進行的,如上文所言,CLR首先做的是遍歷catch,當(dāng)找到合適的catch塊后,再遍歷與之對應(yīng)finally;而且這個過程會遞歸進行至少兩次,因為編譯器將C#的try…catch…finally翻譯成IL中的兩層嵌套。

??? 當(dāng)然如果沒有找到對應(yīng)的catch塊,那么CLR會直接執(zhí)行finally,然后立即中斷所有線程。Finally塊中的代碼肯定會被執(zhí)行,無論try是否檢測到了異常。

● 性能影響與改進建議

??? 異常捕獲與處理是有性能代價的,雖然這種代價在托管環(huán)境中度量起來比較困難,但是這個過程畢竟經(jīng)過一系列的遍歷。所以僅從性能方面考慮,一般建議有以下幾點準(zhǔn)則:

??????? 1.盡量給CLR一個明確的異常信息,不要使用Exception去過濾異常

??????? 2.盡量不要將try…catch寫在循環(huán)中

??????? 3. try盡量少的代碼,如果有必要可以使用多個catch塊,并且將最有可能拋出的異常類型,書寫在距離try最近的位置

??????? 4.不要只聲明一個Exception對象,而不去處理它

?????? 5.使用性能計數(shù)器實用工具的“CLR Exceptions”檢測異常情況,并適當(dāng)優(yōu)化

??????? 6.使用成員的Try-Parse模式,如果拋出異常,那么用false代替它

四.關(guān)于字符串拼接

??? ● 機制分析

??? .Net字符串型的變量有一個很特殊的機制,這個機制叫做“字符串的駐留”,其變現(xiàn)為字符串恒定不可改變。

??? 簡單的說,字符串一旦建立,就會永久駐留在內(nèi)存中,當(dāng)你修改這個字符串變量時,CLR會在內(nèi)存中新建一個新值,并不會修改舊值,舊值只有被垃圾回收器回收后,那部分被占用的空間才會釋放掉。

??? 這樣設(shè)計的目的無疑是為了提高字符串型變量的建立,因為新建字符串型變量時,CLR首先做的是在“駐留池”中遍歷是否有相同的值的字符串,如果有則直接掛接變量指針,否則才會新建,但是在某些情況下,性能卻反而降低。

??? ● 性能影響與改進建議

??? 下面通過例子簡單的說一下字符串駐留機制,假設(shè)有如下代碼:

string str = "";

string a = "str_1" + str;

a = "str_2"+ str;

??? 第三行C#代碼(a = "str_2"+ str;)的樣子看起來是在修改變量a的舊值"str_1",但實際上是創(chuàng)建了一個新的字符串"str_2",然后將變量a的指針指向了"str_2"的內(nèi)存地址,而"str_1"依然在內(nèi)存中沒有受到任何影響 ---這就是字符串的駐留,如果下一次有變量b的值被賦值為“str_1”,CLR不會重新為這個變量重新分配內(nèi)存,而是直接將該變量的指針指向“str_1”,這樣就提高了該變量的初始化速度,但是如果沒有這樣的一個b變量,那么“str_1”就會一直占用內(nèi)存,直至垃圾收集,這樣做浪費了內(nèi)存資源。關(guān)于字符串的各項特性,請參考Aicken以前的文章:

????.Net Discovery 系列之八--string從入門到精通(勘誤版上)

????.Net Discovery 系列之九--string從入門到精通(勘誤版下)

??? 同樣ToUpper、SubString、Trim、Replace、加號連接等操作都會產(chǎn)生駐留的字符串,各位在設(shè)計程序時要特別注意。

??? 經(jīng)常看到有的同學(xué)使用Replace替換一個網(wǎng)頁整個HTML的某些關(guān)鍵字,其實這樣會極大的浪費內(nèi)存,給垃圾回收器的策略引擎以錯誤的信號,使其頻繁啟動,從而導(dǎo)致性能的降低,關(guān)于策略引擎的相關(guān)話題,請參考:

????.Net Discovery 系列之四--深入理解.Net垃圾收集機制(下)

??? 所以,有以下建議供大家參考:

??????? 1.在用Replace做大量字符串操作時,最好僅僅對最小單元進行操作

??????? 2在盡量少的字符串中替換,有必要時還要配合正則的使用,在替換完畢后最好根據(jù)上下文的代齡情況,手動調(diào)用一次GC的回收方法;

??????? 3.對大規(guī)模的字符串拼接操作,則推薦使用StringBuilder

??????? 4.能用常量賦值的就別用變量。因為常量賦值的字符串是在編譯器生成在“字符串常量池”的,關(guān)于常量池請參考Aicken以前的文章。


本文轉(zhuǎn)自Aicken(李鳴)博客園博客,原文鏈接:http://www.cnblogs.com/isline/archive/2010/04/14/1711677.html,如需轉(zhuǎn)載請自行聯(lián)系原作者

總結(jié)

以上是生活随笔為你收集整理的.Net Discovery系列之十二-深入理解平台机制与性能影响(下)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。