Native Image Generation in Managed Code

This article explains how to write and execute high-performance .NET managed code by employing the Native Image Generator utility as well as some of its disadvantages and recommended scenario guidelines for its use.

Abstract

As an application grows ever more complex, it is necessary to building an efficient and faster .NET application that requires a special treatment of .NET assemblies into the Global Assembly Cache to attain faster execution. This article explains how to write and execute high-performance .NET managed code by employing the Native Image Generator utility. The NGen.exe is a remarkable tool for increasing application performance but some of its disadvantages are also provided and this article provides recommended scenario guidelines in which it is best fitted.

JIT verse Native assembly

Assemblies store code in the MSIL format. When a method is invoked for the first time, the CLR Just-in-Time (JIT) compiler compiles that method into native machine code. The native code is stored in memory and directly used for any subsequent call to this method. In the JIT compilation mode, a method is slow when it is called for the first time because an additional step of compilation is involved, but any subsequent calls to that method will run as fast as the native code itself.

When you view the GAC, note that some assemblies have their type marked as a native image. That implys that these assemblies were precompiled in native code before they were installed in the native image cache. You too, can create a native image for your assembly by using the Native Image Generator Tool, that is installed as a part of .NET framework SDK.

The NGen.exe (Native Image Generation)

The CLR doesn't interpret IL code. Rather, it uses a Just-in-Time (JIT) compiler to compile IL code into native machine code at run time. So it is clearly transpired that conversion of managed code to native code imposes some performance cost such as, during classes, library loading and application start-up. In order to overcome such problems and to make retrieval more responsive, the CLR offers ahead of time JIT compilation using a technology called NGen.

The NGen.exe utility can be found in your framework directory. It enables you to do this ahead of time compilation on the client machine. The outcome of this operation is stored in a central location on the machine called the Native Image Cache. The loader typically knows to look here when loading an assembly or DLL that is signed by a strong name. All of the .NET Framework assemblies are NGen manipulated during install of the Framework itself.

NGen.exe Operation

NGen uses the same code generation tactics that the CLR JIT uses to generate native code. The code that is generated is designed to take advantage of the underlying computer architecture. An NGen image might be unusable due to subtle differences in chip capabilities. Thus, image generation must occur on the client machine as part of the install rather than being done at coding time during deployment. The CLR notices this at load time and will fall back to the runtime JIT. If you apply a NGen operation to your exe file then NGen traverses your application dependencies, generates code for each and stores the image in the native image cache alongside your program.

In version 4.0 or 4.5 of the framework, a new NGen Windows service has been integrated to take care of queuing and managing NGen applications in the background. Which virtually implies that your program can install, add a request to the NGen queue and then exit the installation. The NGen service will then take care of the compilation asynchronously.

The NGen tool has quite a few switches to control the behavior. Running NGen.exe at the command prompt will show detailed usage information for the tool as in the following;

NGen exe Operation

Here is the brief summary of significant switches for operating NGen.exe:

  • Install: The ngen.exe install abc.dll command will JIT compile and install the image for abc.dll and its dependencies into the Native Image Cache.

    NGen exe install

  • Display: By encountering ngen.exe display abc.dll will show you the image status for abc.dll.

    NGen exe display

  • Uninstall: You can run the ngen.exe uninstall abc.dll command to entirely remove the image from the native image cache.

    NGen exe uninstall

  • Update: By executing, ngen.exe update will update any native images that have been invalidated due to a change in an assembly.

  • Queue: Invoking the ngen.exe queue [pause | status | continue] command enables you to manage the queue from the command line by pausing and continuing its status.

    NGen exe queue
Note: Be sure that the Visual Studio command prompt is be run under Administrative privileges to execute NGEN.exe.

NGen.exe Advantage and Disadvantage

Since the code is compiled at install time, the CLR's JIT compilation does not need to compile the IL code at run time and this can improve the application's performance. The ngen.exe tool is advantageous in the following scenarios.

  • Optimizing an application startup time: The ngen surely improves the application startup time because the code will already be compiled into native code so that compilation doesn't need to occur at run time.

  • Reduce an application working set: Some assembly will be loaded into multiple application domains or processes simultaneously. So, the Ngen can reduce the application working set because it compiles the IL to native code and saves the output in a separate file. This file can be memory-mapped into multiple process address spaces simultaneously.

Despite providing a couple of benefits of managed code, such as garbage collection, verification and type safety, without hitting the performance problem, there are several potential issues addressed by an NGen'd file such as:

  • Less of Intellectual Property Protection: It is not possible to keep the intellectual property secret by shipping NGen'd files without the files containing the original IL code. At run time, the CLR requires access to the assembly metadata.

  • Out of Sync: When the CLR loads an NGen'd file, it compares a number of characteristics about the previously compiled code. If any don't match then the NGen'd file cannot be used and the normal JIT compiler process is used instead.

  • Substandard Load-Time Performance: Every assembly file is a standard Windows PE standard file and each contains a preferred base address. When Windows loads an NGen'd file, it checks to see if the file loads at its preferred base address. If it is not loaded with a base address, Windows relocates the files, fixing up all of the memory references. This process is extremely resource and time consuming.

  • The .NET Framework 2.0 includes a version of Ngen.exe that produces images that can be shared among application domains. Ngen.exe is not recommended for ASP.NET version 1.0 and 1.1 because the assemblies that Ngen.exe produces cannot be shared between application domains.
Significant Guidelines for NGen
  • It is recommended to measure the application performance with and without Ngen.exe.

  • Regenerate your image when you ship new versions.

  • Choose an appropriate base address for an assembly.

  • Scenarios in which it will be best fitted is the ability to share assemblies should adopt Ngen.exe.

  • Scenarios with limited or no sharing should not use Ngen.exe.

  • Do not use Ngen.exe for ASP.NET version 1.0 and 1.1. Instead consider it for ASP.NET version 2.0.

Final Note

Due to all the issues related to an NGen'd file, you should be very cautious when considering the use of NGen.exe. For a client application, it might make sense to improve startup time if an assembly is used by multiple applications simultaneously. The CLR will not need to load the JIT compiler at all, reducing the working set even further. For server applications, NGen.exe makes no sense because only the first client request experiences a performance hit, future requests run at high speed.