C#学习经验之如何释放非托管资源?
.NET 平台在内存管理方面提供了GC(Garbage Collection),负责自动释放托管资源和内存回收的工作,但它无法对非托管资源进行释放,这时我们必须自己提供方法来释放对象内分配的非托管资源,比如你在对象的实现代码中使用了一个COM对象
最简单的办法,可以通过实现protected void Finalize()(析构函数会在编译时变成这个东东)来释放非托管资源,因为GC在释放对象时会检查该对象是否实现了 Finalize() 方法,如果是则调用它。但,据说这样会降低效率……
有一种更好的,那就是通过实现一个接口显式的提供给客户调用端手工释放对象的方法,而不是傻傻的等着GC来释放我们的对象(何况效率又那么低)
System 命名空间内有一个 IDisposable 接口,拿来做这事非常合适,就省得我们自己再声明一个接口了
另外补充一句,这种实现并不一定要使用了非托管资源后才用,如果你设计的类会在运行时有大些的实例(象 GIS 中的Geometry),为了优化程序性能,你也可以通过实现该接口让客户调用端在确认不需要这些对象时手工释放它们
示例:
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace Example20 {
- class Program {
- class Class1 : IDisposable {
- //析构函数,编译后变成 protected void Finalize(),
GC会在回收对象前会调用调用该方法~Class1(){- Dispose(false);
- }
- //通过实现该接口,客户可以显式地释放对象,而不需要等待GC来释放资源,
据说那样会降低效率void IDisposable.Dispose(){- Dispose(true);
- }
- //将释放非托管资源设计成一个虚函数,提供在继承类中释放基类的资源的能力
- protected virtual void ReleaseUnmanageResources({
- //Do something……
- }
- //私有函数用以释放非托管资源private void Dispose(bool disposing){
- ReleaseUnmanageResources();
- //为true时表示是客户显式调用了释放函数,需通知GC不要再调用对象的Finalize方法
- //为false时肯定是GC调用了对象的Finalize方法,
所以没有必要再告诉GC你不要调用我的Finalize方法啦if (disposing{- GC.SuppressFinalize(this);} static void Main(string[] args){
- //tmpObj1没有手工释放资源,就等着GC来慢慢的释放它吧Class1 tmpObj1 = new Class1();
- //tmpObj2调用了Dispose方法,传说比等着GC来释放它效率要调一些
- //个人认为是因为要逐个对象的查看其元数据,以确认是否实现了Dispose方法吧
- //当然最重要的是我们可以自己确定释放的时间以节省内存,优化程序运行效率
- Class1 tmpObj2 = new Class1()((IDisposable)tmpObj2)。Dispose();
- }
C#学习经验之P/Invoke是什么?
在受控代码与非受控代码进行交互时会产生一个事务(transition) ,这通常发生在使用平台调用服务(Platform Invocation Services),即P/Invoke
如调用系统的 API 或与 COM 对象打交道,通过 System.Runtime.InteropServices 命名空间,虽然使用 Interop 非常方便,但据估计每次调用事务都要执行 10 到 40 条指令,算起来开销也不少,所以我们要尽量少调用事务,如果非用不可,建议本着一次调用执行多个动作,而不是多次调用每次只执行少量动作的原则。
C#学习经验之StringBuilder 和 String 的区别?
String 虽然是一个引用类型,但在赋值操作时会产生一个新的对象,而 StringBuilder 则不会,所以在大量字符串拼接或频繁对某一字符串进行操作时***使用 StringBuilder,不要使用 String
示例:
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace Example22 {
- class Program {
- static void Main(string[] args){
- const int cycle = 100000;
- long vTickCount = Environment.TickCount;
- String str = null;
- for (int i = 0; i < cycle; i++)
- str += i.ToString();
- Console.WriteLine
("String: {0} MSEL", Environment.TickCount - vTickCount);- vTickCount = Environment.TickCount;
- //看到这个变量名我就生气,奇怪为什么大家都使它呢? :)
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < cycle; i++)
- sb.Append(i);
- Console.WriteLine
("StringBuilder: {0} MSEL", Environment.TickCount - vTickCount);- Console.ReadLine();
- }
【编辑推荐】