1 * Writing performant .NET and Mono applications
3 The following document contains a few hints on how to improve
4 the performance of your Mono/.NET applications.
6 These are just guidelines, and you should still profile your
7 code to find the actual performance problems in your
10 ** Using the Mono profiler
12 To obtain memory consumption and measure the time spent on
13 functions and the number of times a function is called in
14 Mono, you can invoke the runtime with the --profile flag, like this:
17 mono --profile program.exe
20 The above will instruct Mono to instrument your application
21 for profiling. The default Mono profiler will record the time
22 spent on a routine, the number of times the routine called,
23 the memory consumed by each method broken down by invoker, and
24 the total amount of memory consumed, this is what it looks
27 Total time spent compiling 227 methods (sec): 0.07154
28 Slowest method to compile (sec): 0.01893: System.Console::.cctor()
29 Time(ms) Count P/call(ms) Method name
30 ########################
31 91.681 1 91.681 .DebugOne::Main()
32 Callers (with count) that contribute at least for 1%:
33 1 100 % .DebugOne::Main(object,intptr,intptr)
35 Total number of calls: 3741
39 ########################
40 406 KB .DebugOne::Main()
41 406 KB 1000 System.Int32[]
42 Callers (with count) that contribute at least for 1%:
43 1 100 % .DebugOne::Main(object,intptr,intptr)
44 Total memory allocated: 448 KB
47 You might want to keep a close eye on the memory consumption
48 and on the method invocation counts. A lot of the
49 performance gains in MCS for example came from reducing its
50 memory usage, as opposed to changes in the execution path.
52 ** Memory Management in the .NET/Mono world.
54 Since Mono and .NET offer automatic garbage collection, the
55 programmer is freed from having to track and dispose the
56 objects it consumes (except for IDispose-like classes). This
57 is a great productivity gain, but if you create thousands of
58 objects, that will make the garbage collector do more work,
59 and it might slow down your application.
63 The <tt>foreach</tt> C# statement handles various kinds of
64 different constructs (about seven different code patterns are
65 generated). Typically foreach generates more efficient code
66 than loops constructed manually, and also ensures that objects
67 which implement IDispose are properly released.
69 But foreach sometimes might generate code that under stress
70 performs badly. Foreach performs badly when its used in tight
71 loops, and its use leads to the creation of many enumerators.
72 Although technically obtaining an enumerator for some objects
73 like ArrayList is more efficient than using the ArrayList
74 indexer, the pressure introduced due to the extra memory
75 requirements and the demands on the garbage collector make it
78 There is no straight-forward rule on when to use foreach, and
79 when to use a manual loop. The best thing to do is to always
80 use foreach, and only when profile shows a problem, replace
81 foreach with for loops.
83 *** Using structs instead of classes for small objects
85 For small objects, you might want to consider using value
86 types (structs) instead of object (classes).
88 ** Assisting the Garbage Collector
90 Although the Garbage Collector will do the right thing in
91 terms of releasing and finalizing objects on time, you can
92 assist the garbage collector by clearing the fields that
93 points to objects. This means that some objects might be
94 elegible for collection earlier than they would, this can help
95 reduce the memory consumption and reduce the work that the GC