将一个成员要领注册到某个对象的事宜会形成后者持有前者的援用。在事宜注销之前,前者不会被垃圾接纳。
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占用
反射手艺是将编译时期的静态绑定转换为延晚到运转时期的动态绑定。
C#重要支撑 5 种动态建立对象的体式格局(时候斲丧来自收集,与我实测的差异挺大,详细测试见下方):
动态建立对象的体式格局 |
与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、序列化与反序列化
相关于XML、二进制序列化体式格局,Protobuf效力较高,支撑数据量较大
protobuf序列化后的大小是json的1/10,xml花样的1/20,是二进制序列化的1/10
以上就是C# 机能优化最好实践的内容,更多相关内容请关注ki4网(www.ki4.cn)!