- 1 Common reasons of low performance in .Net Applications
- 2 How to fix common reasons of performance loss in .Net assemblies
- 3 Other tricks to increase performance in .Net
Common reasons of low performance in .Net Applications
Application written on .Net is not CPU executable by its own.
The reason is that .Net programm is an assembly on MSIL code. MSIL is a an assembly language (some similar to assembler). Every .Net application consists of MSIL commands. Before app is executed CLR platform translates MSIL codes into native CPU commands by means of JIT compiler. On one side, this process takes some time. For instance, that is why c++ programm launches and works faster that c# assembly. On the other side, MSIL is cross-platform because CLR is in charge of building correct CPU commands. Thus you can launch .Net project on every computer that supports CLR, unlike c++ app that should be recompiled for different CPUs.
Impact on work of GC in the wrong hands.
GC is a garbage collector, soft, which is responsible for deletion of unused objects from memory. By default it works fine in most cases: erases unlinked data in RAM when application needs more memory. Sometimes you may think that you need to use some functions of GC during the runtime. It is absolutely possible, but misusing GC can harm the performance.
Unoptimized boxing and unboxing objects.
As far as we concerned, data types is diverged into value types and reference types. Also it is possible to make a reference type of a value type (boxing) and a value type of a refence type (unboxing). This operations consume memory and CPU resources and should be avoided when it is possible.
Unoptimized usage of threads.
Dealing with long tasks in one thread application blocks UI interface (if it is used). Besides it surely takes more time than in multy thread applicaton, when it is possible to split tasks to different workflows.
Operations with large Arrays in c#.
In general, Array is used to store a collection of elements. But, if it comes to adding elements to a large collection, array consumes a lot of resources. As array is a defined sequence of “places” in memory, it can’t be easilly resized: firstly, new array with needed length is created; secondly, the previous array is copied in the new one; finally, it can take new elements.
Debugging of .Net assembly is performed by means of an extra commands that are inserted in MSIL code after compilation. Therefore it is possible to set break points, add break conditions and so on. All debug tricks consume extra resources.
x86 configuration of application.
In brief, the difference between x86 and x64 systems is the amount of memory CPU can access and process. x86 architecture systems can operate with less amount of memory during inner ariphmetical operations and can access to less amount of data from RAM than x64 systems. By the way x86 soft is compatible with x64 machines.
How to fix common reasons of performance loss in .Net assemblies
.Net native compiles UWP assembly directly to CPU native code.
.Net Native is a technology that is used to compile UWP projects for Windows 10 directly to machine code. It gives such advantages as:
- Increased speed of execution
- Rapid launch of application
- Enhanced memory usage
To use .Net Native you need to:
- Create UWP project
- Enable .Net Native in properties
- Build the project
Don’t call GC when it is not necessary. Make hints for GC using destructors. Take care of unmanaged resources by means of IDisposable interface.
The ground of memory managging:
- GC decides independently when and what object should be deleted from the heap by its rules.
- Deconstructor of an object (some class examplar) is a method that is called by GC before it deletes the object.
- IDisposable is an interface that is used in disposing pattern. IDisposable objects have Dispose method that should be used to clean unmanaged resources after object does its job. Dispose method is not called by GC.
- You can controll the behaviour of garbage collector by means of GC class.
To perform several tasks at the same time application needs to create several threads. Asyncronous tasks can increase the performance and solve the problem with blocked UI.
Usually application is running in a single threaded mode. Also if asynchronous tools are not used, work flows in a synchronic manner. The ground of threading:
- Threading namespace.
- class Thread – let’s to create and control threads. The creation of thread is resource taking process, therefore too many started threads may decrease the performance. If your machine has many CPU cores, you can perform commands in defferent threads in parallel.
- As starting new thread is a resource expensive thing, you can borrow some thrreads from ThreadPool
- If your machine doesn’t have many CPU cores or parallel work is not necessary there is no need to use threads as it is. Alternativelly, the better option is to use class Task. Basically, Task is superstructure over Thread. In addition it supports very simple control over Asyncronous workflow. Asynncronous tasks can
be performed in parallel, but in general CPU splits async tasks into several parts and executes them one by one as it considers. This solves problem with blocked UI and boosts performance.
Big arrays take too many resources on resize.
The better alternative to large array is List<T> collection. It can easilly perform adding, removing and resizing.
RELEASE version of application is certainly more performant than DEBUG.
To build a project in release mode, turn it on in visual studio.
x64 systems are more performant than x86.
To build assebly in x64 configuration, turn it on in visual studio.