托管代码 (managed code)
托管代码是由公共语言运行库环境(而不是直接由操作系统)执行的代码。托管代码应用程序可以获得公共语言运行库服务,例如自动垃圾回收、运行库类型检查和安全支持等。这些服务帮助提供独立于平台和语言的、统一的托管代码应用程序行为
非托管代码 (unmanaged code)
在公共语言运行库环境的外部,由操作系统直接执行的代码。非托管代码必须提供自己的垃圾回收、类型检查、安全支持等服务;它与托管代码不同,后者从公共语言运行库中获得这些服务。
托管代码就是基于.net元数据格式的代码,运行于.net平台之上,所有的与操作系统的交换有.net来完成,就像是把这些功能委托给.net,所以称之为托管代码。非托管代码则反之。
托管资源
托管资源是由公共语言运行的垃圾回收器进行分配和释放的数据(如int,string,float,DateTime等等,.net中超过80%的资源都是托管资源)。默认情况下, C#、Visual Basic 和 JScript.NET 数据是托管资源。不过,通过使用特殊的关键字,C# 数据可以被标记为非托管资源。Visual C++数据在默认情况下是非托管数据,即使在使用 /CLR 开关时也不是托管的。
非托管资源
非托管资源是CLR不能控制或者管理的部分。 最常见的一类非托管资源就是包装操作系统资源的对象(如文件,窗口或网络连接),对于非托管资源虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源,所以需要手动释放。
常见的非托管资源:ApplicationContext,Brush,Component,ComponentDesigner,Container,Context,Cursor,FileStream,Font,Icon,Image,Matrix,Object,OdbcDataReader,OleDBDataReader,Pen,Regex,Socket,StreamWriter,Timer,Tooltip 等资源
.Net类型分为两大类,一个就是值类型,另一个就是引用类型。对于值类型是分配在栈上的,因此并不需要GC回收,而引用类型是分配在堆上的,需要GC来回收。
.NET中托管资源虽然由GC自动回收并不需要手动释放,但前提是要告诉GC该托管资源已经是垃圾。如果一个引用类型的对象或者其所包还的子对象没有任何引用是有效的,就认为该对象是垃圾(也就是可以被GC自动回收)。
托管资源也回存在内存泄露的问题,如果对象间存在交叉引用,则该对象无法被GC所回收。所以在确定一个对象不再使用(需要释放时)需要确定该对象没有被其他对象所引用。
.Net提供如下几种常用方法:
使用using 语句获得一个或多个资源,执行指定的代码,在代码超出using语句的作用范围时,using语句会自动隐式调用该对象的Dispose()方法来释放对象(如代码A)。
使用using程序块的两个限制
可以有多个对象与 using 语句一起使用,但是必须在 using 语句内部声明这些对象 。
A:
1 | Font font2 = new Font("Arial", 10.0f); |
2 | using (font2) |
3 | { |
4 | // use font2 |
5 | } |
6 |
B:
1 | using (Font font3 = new Font("Arial", 10.0f), |
2 | font4 = new Font("Arial", 10.0f)) |
3 | { |
4 | // Use font3 and font4. |
5 | } |
6 |
C:
1 | Font font2 = new Font("Arial", 10.0f); |
2 | Object font5=font2 ; |
3 | using (font5) |
4 | { |
5 | // use font2 |
6 | } |
7 |
1.2 try/finally 块
1 | Font font2; |
2 | try |
3 | { |
4 | font2 = new Font("Arial", 10.0f); |
5 | // use font2 |
6 | } |
7 | finally |
8 | { |
9 | if(font2!=null) |
10 | font2.Dispose(); |
11 | } |
12 |
c#的析构函数有一下限制 :
下面(代码A)是类 Car 的析构函数的声明,该析构函数代码被隐式地转换为(代码B):
A:
1 | class Car |
2 | { |
3 | ~ Car() // destructor |
4 | { |
5 | // cleanup statements... |
6 | } |
7 | } |
8 |
B:
1 | protected override void Finalize() |
2 | { |
3 | try |
4 | { |
5 | // cleanup statements... |
6 | } |
7 | finally |
8 | { |
9 | base.Finalize(); |
10 | } |
11 | } |
12 |
注意点:
MSDN建议按照下面的模式实现IDisposable接口:
1 | public class Foo: IDisposable |
2 | { |
3 | public void Dispose() |
4 | { |
5 | Dispose(true); |
6 | GC.SuppressFinalize(this); |
7 | } |
8 | |
9 | protected virtual void Dispose(bool disposing) |
10 | { |
11 | if (!m_disposed) |
12 | { |
13 | if (disposing) |
14 | { |
15 | // Release managed resources |
16 | } |
17 | |
18 | // Release unmanaged resources |
19 | |
20 | m_disposed = true; |
21 | } |
22 | } |
23 | |
24 | ~Foo() |
25 | { |
26 | Dispose(false); |
27 | } |
28 | |
29 | private bool m_disposed; |
30 | } |
31 |
有时特定于域的名称比 Dispose 更合适。例如,文件封装可能需要使用 Close 方法名称。在此情况下,可以通过专用方式实现 Dispose 并创建调用 Dispose 的公共Close 方法。下面的代码示例阐释了这种模式。可以用适合您的域的方法名称替换 Close。此示例需要 System 命名空间。
1 | // Do not make this method virtual. |
2 | // A derived class should not be allowed |
3 | // to override this method. |
4 | public void Close() |
5 | { |
6 | // Call the Dispose method with no parameters. |
7 | Dispose(); |
8 | } |
9 |