Performance Tips and Tricks in .NET Applications(五)

发表于:2007-06-30来源:作者:点击数: 标签:
What You Can Do At every phase of development, there are several things you can do. With MC++, the design phase is perhaps the most import ant area, as it will determine how much work you end up doing and how much performance you get in re

What You Can Do


At every phase of development, there are several things you can do. With MC++, the design phase is perhaps the most important area, as it will determine how much work you end up doing and how much performance you get in return. When you sit down to write or port an application, you should consider the following things:
  • Identify areas where you use multiple inheritance, templates, or deterministic finalization. You will have to get rid of these, or else leave that part of your code in unmanaged space. Think about the cost of redesigning, and identify areas that can be ported.
  • Locate performance hot spots, such as deep abstractions or virtual function calls across managed space. These will also require a design decision.
  • Look for objects that have been specified as stack-managed. Make sure they can be converted into ValueTypes. Mark the others for conversion to heap-managed objects.

During the coding stage, you should be aware of the operations that are more expensive and the options you have in dealing with them. One of the nicest things about MC++ is that you come to grips with all the performance issues up front, before you start coding: this is helpful in paring down work later on. However, there are still some tweaks you can perform while you code and debug.
Determine which areas make heavy use of floating point arithmetic, multidimensional arrays or library functions. Which of these areas are performance critical? Use profilers to pick the fragments where the overhead is costing you most, and pick which option seems best:
  • Keep the whole fragment in unmanaged space.
  • Use static casts on the library aclearcase/" target="_blank" >ccesses.
  • Try tweaking boxing/unboxing behavior (explained later).
  • Code your own structure.

Finally, work to minimize the number of transitions you make. If you have some unmanaged code or an interop call sitting in a loop, make the entire loop unmanaged. That way you@#ll only pay the transition cost twice, rather than for each iteration of the loop.

Additional Resources


Related topics on performance in the .NET Framework include:

Watch for future articles currently under development, including an overview of design, architectural and coding philosophies, a walkthrough of performance analysis tools in the managed world, and a performance comparison of .NET to other enterprise applications available today.

Appendix: Cost of Virtual Calls and Allocations

Call Type# Calls/sec
ValueType Non-Virtual Call809971805.600
Class Non-Virtual Call268478412.546
Class Virtual Call109117738.369
ValueType Virtual (Obj Method) Call3004286.205
ValueType Virtual (Overridden Obj Method) Call2917140.844
Load Type by Newing (Non-Static)1434.720
Load Type by Newing (Virtual Methods)1369.863

Note   The test machine is a PIII 733Mhz, running Windows 2000 Professional with Service Pack 2.
This chart compares the cost associated with different types of method calls, as well as the cost of instantiating a type that contains virtual methods. The higher the number, the more calls/instantiations-per-second can be performed. While these numbers will certainly vary on different machines and configurations, the relative cost of performing one call over another remains significant.
  • ValueType Non-Virtual Call: This test calls an empty non-virtual method contained within a ValueType.
  • Class Non-Virtual Call: This test calls an empty non-virtual method contained within a class.
  • Class Virtual Call: This test calls an empty virtual method contained within a class.
  • ValueType Virtual (Obj Method) Call: This test calls ToString() (a virtual method) on a ValueType, which resorts to the default object method.
  • ValueType Virtual (Overridden Obj Method) Call: This test calls ToString() (a virtual method) on a ValueType that has overridden the default.
  • Load Type by Newing (Static): This test allocates space for a class with only static methods.
  • Load Type by Newing (Virtual Methods): This test allocates space for a class with virtual methods.

One conclusion you can draw is that Virtual Function calls are about two times as expensive as regular calls when you@#re calling a method in a class. Bear in mind that calls are cheap to begin with, so I wouldn@#t remove all virtual calls. You should always use virtual methods when it makes sense to do so.
  • The JIT cannot inline virtual methods, so you lose a potential optimization if you get rid of non-virtual methods.
  • Allocating space for an object that has virtual methods is slightly slower than the allocation for an object without them, since extra work must be done to find space for the virtual tables.

Notice that calling a non-virtual method within a ValueType is more than three times as fast as in a class, but once you treat it as a class you lose terribly. This is characteristic of ValueTypes: treat them like structs and they@#re lighting fast. Treat them like classes and they@#re painfully slow. ToString() is a virtual method, so before it can be called, the struct must be converted to an object on the heap. Instead of being twice as slow, calling a virtual method on a ValueType is now eighteen times as slow! The moral of the story? Don@#t treat ValueTypes as classes.
If you have questions or comments about this article, contact Mahesh Prakriya(), program manager for .NET Framework performance issues.

原文转自:http://www.ltesting.net