1、顯式註冊的EvenHandler要顯式登出以避免記憶體流失
將一個成員方法註冊到某個對象的事件會造成後者持有前者的引用。在事件登出之前,前者不會被記憶體回收。
private void Form1_Load(){ …… //註冊事件 CommandRemotingContext.CmdChanged += new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged); ……}private void Form1_FromClosed(){ …… //關閉表單時及時釋放事件 CommandRemotingContext.CmdChanged -= new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged); ……}
由事件引起的記憶體流失問題:
對象A訂閱了對象B中的事件
對象A的生命週期遠遠大於對象B
對象A沒有取消訂閱對象B的時間
最終導致對象B無法釋放
2、控制項繫結資料源大量操作應避免自動重新整理
用戶端大量操作資料時,控制項內建的重新整理操作,會造成不必要的時間消耗
當資料來源(如DataTable、Array、List、ObservableCollection或其他IListSource等)被綁定到控制項時,大量操作資料時應該斷開綁定或掛起控制項的重新整理。
this.gcBillList.DataSource = null;DataRowCollection rows = this.ds.Tables[0].Rows;foreach (DataRow row in rows){ // DataRow資料操作}this.gcBillList.DataSource = this.ds.Tables[0].DefaultView;
3、減少用戶端與服務端的通訊次數
WebService調用並非越少越好,傳輸資料量較大的情況可考慮拆分為多次調用
對於短WebService的調用,應盡量合并以減少互動次數
//多次調用了相同的WS txtCompanyName.Text=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyNameByID”,“0001”); txtCompanyInnerName.Text=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyInnerNameByID”,“0001”);//合并相鄰的WS string[] result=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyNameAndInnerNameByID”,“0001”);txtCompanyName.Text=result[0];txtCompanyInnerName.Text= result[1];
4、減少用戶端與服務端的通訊次數
如非必要,應盡量避免在迴圈體內重複調用WebService
//迴圈調用了相同的WS List<Person> persons;……foreach(string personID in personIDs){person=HRPubWsClient.getPerson(personID);persons.Add(person);}//合并WS List<Person> persons;……persons =HRPubWsClient.getPersonList(personIDs);
5、使用泛型來避免裝箱、拆箱操作(減少記憶體回收壓力)
裝箱操作會造成GC壓力;如果發生在集合中,應該使用泛型集合避免。
對於實值型別的集合,使用List<T>來代替ArrayList,使用Dictionary<TKey, TValue> 來代替Hashtable。
ArrayList h=new ArrayList(); //不建議h.Add(1); List<object> h = new List<object>(); //不建議h.Add(1); List<int> h = new List<int>(); //建議h.Add(1);
6、字串操作:
C# 字串操作--減少記憶體回收壓力
7、使用常量避免建立對象
如下例,程式中存在大量 new decimal(0)的代碼,這會導致小對象頻繁建立及回收;正確的做法是使用 Decimal.Zero 常量。
private string CurrencyCalc(){ if (firstValue == new decimal(0)) …… if (secondValue == new decimal(0)) …… if (thirdValue == new decimal(0)) …… if (fourthValue == new decimal(0)) …… ……}
8、避免不必要的拋出異常
C# 異常處理(Catch Throw)IL分析
9、使用RemoveAll而非RemoveAt進行刪除多個元素
使用RemoveAll方法對集合(如List)中的多個元素進行一次性刪除時,只會對List的內部數組做一次resize 操作,效率明顯高於迴圈調用RemoveAt。
List<string> lst = new List<string> {"1", "2", "3", "1", "2", "4"};//不建議:for (int i = lst.Count - 1; i >= 0; i--){ if (lst[i] == "1" || lst[i] == "2") { lst.RemoveAt(i); }} //建議:lst.RemoveAll(s => s == "1" || s == "2");
10、C# DataSet效能最佳實務
11、反射與動態綁定--減少CPU佔用
動態建立對象的方式
|
與Direct Create
|
1.Type.InvokeMember
|
慢40倍以上
|
2.ContructorInfo.Invoke
|
慢40倍以上
|
3.Activator.CreateInstance(Type)
|
慢7倍
|
4.Activator.CreateInstance(assemblyName, typeName)
|
慢1000倍以上
|
5.Assembly.CreateInstance(typeName)
|
慢40倍以上 |
1. 使用介面調用方式將動態綁定改造為早期繫結(Direct Call)
2. 使用 Activator.CreateInstance(Type)方式動態建立對象
3. 使用typeof操作符代替GetType調用
小註:
通過迴圈建立執行個體記錄時間如下:
載入程式集、擷取類型在迴圈外部時間如下(這時不同建立方式消耗時間差距挺大):
代碼如下:
public void TestCreateInstance() { Stopwatch watch1 = new Stopwatch(); var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); Type type = asmb.GetType("ReflectiveClassLibrary.TestClass"); int num = 100000; watch1.Start(); for (int i = 0; i < num; i++) { //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass"); Activator.CreateInstance(type); } watch1.Stop(); label1.Text = "Activator.CreateInstance(Type type)時間:" + watch1.ElapsedMilliseconds + "毫秒"; watch1.Reset(); watch1.Start(); for (int i = 0; i < num; i++) { Activator.CreateInstance("ReflectiveClassLibrary", "ReflectiveClassLibrary.TestClass"); } watch1.Stop(); label2.Text = "Activator.CreateInstance(string assemblyName,string typeName)時間:" + watch1.ElapsedMilliseconds + "毫秒"; watch1.Reset(); watch1.Start(); for (int i = 0; i < num; i++) { //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); //載入程式集 asmb.CreateInstance("TestClass"); } watch1.Stop(); label3.Text = "assembly.CreateInstance(string typeName)時間:" + watch1.ElapsedMilliseconds + "毫秒"; watch1.Reset(); watch1.Start(); for (int i = 0; i < num; i++) { //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass"); object obj = type.InvokeMember(null, BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null); } watch1.Stop(); label4.Text = "Type.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args)時間:" + watch1.ElapsedMilliseconds + "毫秒"; watch1.Reset(); watch1.Start(); for (int i = 0; i < num; i++) { //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass"); ConstructorInfo constructorInfo = type.GetConstructors()[0]; constructorInfo.Invoke(null); } watch1.Stop(); label5.Text = "ContructorInfo.Invoke(object[] parameters)時間:" + watch1.ElapsedMilliseconds + "毫秒"; }
載入程式集、擷取類型在迴圈內部時間如下(這時不同建立方式消耗時間差距比較小):
代碼如下:
public void TestCreateInstance() { Stopwatch watch1 = new Stopwatch(); //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass"); int num = 100000; watch1.Start(); for (int i = 0; i < num; i++) { var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); Type type = asmb.GetType("ReflectiveClassLibrary.TestClass"); Activator.CreateInstance(type); } watch1.Stop(); label1.Text = "Activator.CreateInstance(Type type)時間:" + watch1.ElapsedMilliseconds + "毫秒"; watch1.Reset(); watch1.Start(); for (int i = 0; i < num; i++) { Activator.CreateInstance("ReflectiveClassLibrary", "ReflectiveClassLibrary.TestClass"); } watch1.Stop(); label2.Text = "Activator.CreateInstance(string assemblyName,string typeName)時間:" + watch1.ElapsedMilliseconds + "毫秒"; watch1.Reset(); watch1.Start(); for (int i = 0; i < num; i++) { var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); //載入程式集 asmb.CreateInstance("TestClass"); } watch1.Stop(); label3.Text = "assembly.CreateInstance(string typeName)時間:" + watch1.ElapsedMilliseconds + "毫秒"; watch1.Reset(); watch1.Start(); for (int i = 0; i < num; i++) { var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); Type type = asmb.GetType("ReflectiveClassLibrary.TestClass"); object obj = type.InvokeMember(null, BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null); } watch1.Stop(); label4.Text = "Type.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args)時間:" + watch1.ElapsedMilliseconds + "毫秒"; watch1.Reset(); watch1.Start(); for (int i = 0; i < num; i++) { var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll"); Type type = asmb.GetType("ReflectiveClassLibrary.TestClass"); ConstructorInfo constructorInfo = type.GetConstructors()[0]; constructorInfo.Invoke(null); } watch1.Stop(); label5.Text = "ContructorInfo.Invoke(object[] parameters)時間:" + watch1.ElapsedMilliseconds + "毫秒"; }
測試代碼如下:
c# 反射測試demo
12、序列化與還原序列化
以上就是C# 效能最佳化最佳實務的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!