| | | | | | | [文章信息] | | | 作者: | Gregor Noriskin | | 时间: | 2003-08-28 | | 出处: | 微软 | | 责任编辑: | 方舟 | |
| [文章导读] | | | 学习如何找出托管代码性能的最佳方法,以及如何测量托管应用程序的性能...... | |
| |
|
| | | |
|
|
|
|
|
值类型
CLR 可提供两组不同的类型:引用类型和值类型。引用类型总是分配到托管堆中,并按引用传递(正如它的名称所暗示的)。值类型分配到栈中或在堆中内联为对象的一部分,默认情况下按值传递,不过您也可以按引用来传递它们。分配值类型时,所需的开销非常小,假设它们总是又小又简单,当它们作为参数进行传递时开销也会很小。正确使用值类型的一个很好的示例就是包含 x 和 y 坐标的 Point 值类型。
Point 值类型
struct Point { public int x; public int y;
// } | 值类型也可以视为对象,例如,可以在值类型上调用对象方法,它们可以转换为对象,或传递到需要使用对象的位置。无论使用什么方法,只要将值类型转换为引用类型,都需要经过装箱 (Boxing) 处理。对值类型进行装箱处理时,会在托管堆中分配一个新对象,而值则复制到此新对象中。这项操作将占用很大的系统开销,还可能会降低或完全消除通过使用值类型而获得的性能。将装箱的类型隐式或显式转换回值类型的过程称为取消装箱 (Unboxed)。
装箱/取消装箱值类型
C#:
int BoxUnboxValueType() { int i = 10; object o = (object)i; //i 被装箱 return (int)o + 3; //i 被取消装箱 } | MSIL:
.method private hidebysig instance int32 BoxUnboxValueType() cil managed { // 代码大小 20 (0x14) .maxstack 2 .locals init (int32 V_0, object V_1) IL_0000: ldc.i4.s 10 IL_0002: stloc.0 IL_0003: ldloc.0 IL_0004: box [mscorlib]System.Int32 IL_0009: stloc.1 IL_000a: ldloc.1 IL_000b: unbox [mscorlib]System.Int32 IL_0010: ldind.i4 IL_0011: ldc.i4.3 IL_0012: add IL_0013: ret } // 方法 Class1::BoxUnboxValueType 结束 | 如果实现自定义值类型(C# 中的结构),则应该考虑覆盖 ToString 方法。如果不覆盖此方法,那么对值类型上的 ToString 的调用将导致该类型被装箱。对于从 System.Object 继承的其他方法也是如此。在这种情况下,请使用 Equals 来进行覆盖,尽管 ToString 很可能是最常用的调用方法。如果您希望了解值类型是否被装箱以及何时装箱,可以使用 ildasm.exe 实用程序在 MSIL 中查找 box 指令(如上所述)。
覆盖 C# 中的 ToString() 方法以防止装箱
struct Point { public int x; public int y;
//此操作将防止在调用 ToString 时对类型进行装箱 public override string ToString() { return x.ToString() + "," + y.ToString(); } } | 请注意,在创建集合(例如,浮点数组列表)时,添加到集合中的每一项都将进行装箱。您应该考虑使用数组或为值类型创建自定义集合类。
使用 C# 中的集合类时进行隐式装箱
ArrayList al = new ArrayList(); al.Add(42.0F); //由于 Add() 接受对象因此进行隐式装箱 float f = (float)al[0]; //取消装箱 | 异常处理
通常,错误条件都将作为常规流程控制使用。在此情况下,如果试图通过编程将用户添加到 Active Directory 实例中,则只能试着添加该用户,如果系统返回 E_ADS_OBJECT_EXISTS HRESULT,则说明它们已经存在于该目录中。此外,您也可以通过搜索目录查找该用户,如果搜索失败则只需添加该用户。
按照常规流程控制使用错误,在 CLR 环境中会降低性能。CLR 中的错误处理是借助结构化异常处理实现的。引发异常之前,托管异常的开销非常小。在 CLR 中,引发异常时,需要使用堆栈遍历为已引发的异常找到相应的异常处理程序。堆栈遍历是一种开销较大的操作。正如它的名称所表示的,异常应该用于异常或意外的情况。
提示:对于以性能为中心的方法,请返回预期结果的枚举结果,而不是引发异常。
提示:有多种 .NET CLR 异常性能计数器都可以通知您在应用程序中引发了多少异常。
提示:如果您使用 VB.NET 来使用除 On Error Goto 以外的异常,错误对象就是不必要的开销。
|
|
|
|
|
|
|
|