20.如何手工释放资源?
答:
.NET 平台在内存管理方面提供了GC(Garbage Collection),负责自动释放托管资源和内存回收的工作。但在以下两种情况需要我们手工进行资源释放:一、由于它无法对非托管资源进行释放,所以我们必须自己提供方法来释放对象内分配的非托管资源,比如你在对象的实现代码中使用了一个COM对象;二、你的类在运行是会产生大量实例(象 GIS 中的Geometry),必须自己手工释放这些资源以提高程序的运行效率
示例:
1using System; 2using System.Collections.Generic; 3using System.Text; 4 5namespace Example20 6{ 7 class Program 8 { 9 class Class1 : IDisposable10 {11 //析构函数,编译后变成 protected void Finalize(),GC会在回收对象前会调用调用该方法12 ~Class1()13 {14 Dispose(false);15 }16 17 //通过实现该接口,客户可以显式地释放对象,而不需要等待GC来释放资源,据说那样会降低效率18 void IDisposable.Dispose()19 {20 Dispose(true);21 }22 23 //将释放非托管资源设计成一个虚函数,提供在继承类中释放基类的资源的能力24 protected virtual void ReleaseUnmanageResources()25 {26 //Do something...27 }28 29 //私有函数用以释放非托管资源30 private void Dispose(bool disposing)31 {32 ReleaseUnmanageResources();33 34 //为true时表示是客户显式调用了释放函数,需通知GC不要再调用对象的Finalize方法35 //为false时肯定是GC调用了对象的Finalize方法,所以没有必要再告诉GC你不要调用我的Finalize方法啦36 if (disposing)37 {38 GC.SuppressFinalize(this);39 }40 } 41 }42 static void Main(string[] args)43 {44 //tmpObj1没有手工释放资源,就等着GC来慢慢的释放它吧45 Class1 tmpObj1 = new Class1();46 47 //tmpObj2调用了Dispose方法,传说比等着GC来释放它效率要调一些48 //个人认为是因为要逐个对象的查看其元数据,以确认是否实现了Dispose方法吧49 //当然最重要的是我们可以自己确定释放的时间以节省内存,优化程序运行效率50 Class1 tmpObj2 = new Class1();51 ((IDisposable)tmpObj2).Dispose();52 }53 }54}
21.P/Invoke是什么?
在受控代码与非受控代码进行交互时会产生一个事务(transition) ,这通常发生在使用平台调用服务(Platform Invocation Services),即P/Invoke
如调用系统的 API 或与 COM 对象打交道,通过 System.Runtime.InteropServices 命名空间
虽然使用 Interop 非常方便,但据估计每次调用事务都要执行 10 到 40 条指令,算起来开销也不少,所以我们要尽量少调用事务
如果非用不可,建议本着一次调用执行多个动作,而不是多次调用每次只执行少量动作的原则
22.StringBuilder 和 String 的区别?
String 在进行运算时(如赋值、拼接等)会产生一个新的实例,而 StringBuilder 则不会。所以在大量字符串拼接或频繁对某一字符串进行操作时最好使用 StringBuilder,不要使用 String
另外,对于 String 我们不得不多说几句:
1.它是引用类型,在堆上分配内存
2.运算时会产生一个新的实例
3.String 对象一旦生成不可改变(Immutable)
3.定义相等运算符(== 和 !=)是为了比较 String 对象(而不是引用)的值
1using System; 2using System.Collections.Generic; 3using System.Text; 4 5namespace Example22 6{ 7 class Program 8 { 9 static void Main(string[] args)10 {11 const int cycle = 10000;12 13 long vTickCount = Environment.TickCount;14 String str = null;15 for (int i = 0; i < cycle; i++)16 str += i.ToString();17 Console.WriteLine("String: {0} MSEL", Environment.TickCount - vTickCount);18 19 vTickCount = Environment.TickCount;20 //看到这个变量名我就生气,奇怪为什么大家都使它呢? :)21 StringBuilder sb = new StringBuilder();22 for (int i = 0; i < cycle; i++)23 sb.Append(i);24 Console.WriteLine("StringBuilder: {0} MSEL", Environment.TickCount - vTickCount);25 26 string tmpStr1 = "A";27 string tmpStr2 = tmpStr1;28 Console.WriteLine(tmpStr1);29 Console.WriteLine(tmpStr2);30 //注意后面的输出结果,tmpStr1的值改变并未影响到tmpStr2的值31 tmpStr1 = "B";32 Console.WriteLine(tmpStr1);33 Console.WriteLine(tmpStr2);34 35 Console.ReadLine();36 }37 }38}
结果:String: 375 MSELStringBuilder: 16 MSELAABA
当前平均分: 0.0(0 次打分)