May
9
2013

CLR Memory Diagnostics Released

Last week, Microsoft released the new CLR Memory Diagnostics (ClrMD) library, which is a set of APIs for programmatically inspecting a crash dump of a .NET program.

To start playing with it, you first need to add the Microsoft.Diagnostics.Runtime package from NuGet (be sure to select Include Prerelease, because it is a prerelease version):

You can use ClrMD to analyze a crash dump from disk, or to attach to a live process. In both scenarios, you will need to use one of the static factory methods declared in the DataTarget class. To analyze a crash dump file from disk, start with the following code:

const string pathToFile = @"C:\TestApplication.DMP";
using (DataTarget dataTarget = DataTarget.LoadCrashDump(pathToFile))
{
     // ...
}

To attach to a live process, you need the process's id:

int pid = Process.GetProcessesByName("TestApplication")[0].Id;
using (DataTarget dataTarget = DataTarget.AttachToProcess(pid, 5000))
{
	// ...
}

By default, invasive attachment is used. You can state otherwise by using another overload of the AttachToProcess method that accepts an AttachFlag parameter.

Once attached, the DataTarget object will contain information on the process such as its architecture, loaded CLR versions and loaded modules, but for the really interesting stuff, you will need to create an instance of the ClrRuntime class:

string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation();
if (String.IsNullOrEmpty(dacLocation))
	return;

ClrRuntime runtime = dataTarget.CreateRuntime(dacLocation);

You should pay attention to a few things here:

  1. Multiple CLR versions can be loaded side by side in the same process. DataTarget will contain all of them.
  2. In order to create a ClrRuntime instance, the path to the mscordacwks.dll should be provided.
  3. The TryGetDacLocation method returns the full path to mscordacwks.dll in case that you have it on your machine.
  4. In case that you are analyzing a crash dump, it is possible that you won't have the matching mscordacwks.dll on your machine. In that case, you will need to get it from Microsoft's symbol server (See ClrInfo.DacInfo.FileName). In the rare cases when it's not there, use the method described here.

Once the runtime is created, you can use it for various tasks such as:

  • Inspect the managed heap (all objects, blocking objects, finalizable objects, roots and so on).
  • Inspect the thread pool.
  • Inspect GC Handles.
  • Inspect managed threads (call stack, objects on which the thread is blocked waiting on, current exception, and more).

It's great to have this API as another tool in my debugging tool belt. I'm sure that it will prove itself as valuable in many situations.

Jan
5
2013
.NET // C# // WPF

Setting a WPF Window to be Always on Top

Some applications require that their main window will always be on top of all the other windows. Doing so in WPF is quite simple. In this post I will show how.

In order for the window to be opened on top of all the other windows, set its Topmost property to True. Doing just that is not enough, because when the window will lose its focus, it will be placed behind the focused window. To keep the window top-most even after it loses its focus, add an EventTrigger to the window's LostFocus event, and set the Topmost property to be True again:

<Window x:Class="AlwaysOnTopDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        Topmost="True">
    <Window.Triggers>
        <EventTrigger RoutedEvent="LostFocus">
            <BeginStoryboard>
                <Storyboard>
                    <BooleanAnimationUsingKeyFrames>
                        <DiscreteBooleanKeyFrame KeyTime="0" 
                                                 Value="True" 
                                                 Storyboard.Target="{Binding RelativeSource={RelativeSource AncestorType=Window}}" 
                                                 Storyboard.TargetProperty="Topmost"/>
                    </BooleanAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>
    
    <Grid>
        
    </Grid>
</Window>

Using the same EventTrigger over and over again can be tiring and erroneous. We can save a lot a keystrokes and make the above code reusable by creating a behavior:

using System.Windows;
using System.Windows.Interactivity;

namespace WPFUtils.Behaviors
{
    public class AlwaysOnTopBehavior : Behavior<Window>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.LostFocus += (s, e) => AssociatedObject.Topmost = true;
        }
    }
}

And the usage:

<Window x:Class="WPFUtils.Samples.AlwaysOnTopBehavior.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:behaviors="clr-namespace:WPFUtils.Behaviors;assembly=WPFUtils" 
        Topmost="True"
        Title="AlwaysOnTopBehavior Sample" Height="350" Width="525">
    
    <i:Interaction.Behaviors>
        <behaviors:AlwaysOnTopBehavior/>
    </i:Interaction.Behaviors>
    <Grid>
    </Grid>
</Window>

Keep in mind that using this technique on more than one window will not work, because all the windows will try to set themselves to be top-most, and the one with the focus will win.

The AlwaysOnTopBehavior class is available on GitHub, as part of my WPFUtils project.

Dec
28
2012
.NET // C#

Automatic Properties are not Fields

Even though that the statement in the title is trivial, the fact that the syntax of automatic properties and fields is almost identical can sometimes make us forget that they are two different things. Take, for example, the following struct:

[StructLayout(LayoutKind.Sequential)]
public struct MyData
{
	public int A;
	public int B;
	public int C;
	public int D;
}

Let's assume that it is marshaled and passed to an unmanaged function:

MyData myData = new MyData {A = 1, B = 2, C = 3, D = 4};
IntPtr pData = Marshal.AllocHGlobal(Marshal.SizeOf(myData));
Marshal.StructureToPtr(myData, pData, false);
// Pass pData to some unmanaged function using DllImport

The unmanaged function expects a pointer to a struct that contains 4 integers, where the first integer holds the data for A, the second integer holds the data for B, the third for C, and the forth for D. That is why the struct is decorated with the StructLayout attribute with Sequential LayoutKind, which guides the loader to preserve field order as declared.

What will happen if, for some reason, we implement the C field as an automatic property?

[StructLayout(LayoutKind.Sequential)]
public struct MyData
{
	public int A;
	public int B;
	public int C {get; set;}
	public int D;
}

To answer the question, we need to remember that automatic properties are just a syntactic sugar and when encountered by the compiler, a backing field is automatically generated for them, along with the ordinary get and set methods. The automatically generated backing field will usually be emitted after all the regular fields, and therefore will not preserve the original declaration order.

This is the actual memory layout of the original struct:

0:000> !do 02ef260c
Name:        AutomaticPropertiesLayoutDemo.MyData
MethodTable: 0101389c
EEClass:     01011408
Size:        24(0x18) bytes
File:        E:\Moshe\AutomaticPropertiesLayoutDemo\bin\Debug\AutomaticPropertiesLayoutDemo.exe
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
726cc770  4000007        4         System.Int32  1 instance        1 A
726cc770  4000008        8         System.Int32  1 instance        2 B
726cc770  4000009        c         System.Int32  1 instance        3 C
726cc770  400000a       10         System.Int32  1 instance        4 D

And this is the memory layout of the struct with C implemented as an automatic property:

0:000> !do 02ef26d8  
Name:        AutomaticPropertiesLayoutDemo.MyData
MethodTable: 0101389c
EEClass:     01011408
Size:        24(0x18) bytes
File:        E:\Moshe\AutomaticPropertiesLayoutDemo\bin\Debug\AutomaticPropertiesLayoutDemo.exe
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
726cc770  4000001        4         System.Int32  1 instance        1 A
726cc770  4000002        8         System.Int32  1 instance        2 B
726cc770  4000003        c         System.Int32  1 instance        3 D
726cc770  4000004       10         System.Int32  1 instance        4 <C>k__BackingField

You can see that the compiler has automatically generated a field named <C>k__BackingField, and placed it after the D field, even though it was before it in the struct's declaration. Given the above memory layout, the struct will not be marshaled as expected. Specifically, the C and D fields will change places, causing the unmanaged function to read invalid data. Solving the problem by changing the StructLayout to Explicit is not possible as it will cause the compiler to fail with the following error message: "Automatically implemented properties cannot be used inside a type marked with StructLayout(LayoutKind.Explicit)".

The scenario that I presented is fairly esoteric, but may cause some hard to find bugs. I strongly recommend not to use automatic properties in classes or structs that are used across boundaries.

Dec
13
2012
.NET // C#

Compiler Error: Invalid Character in the Given Encoding

Recently, a colleague of mine received the above compilation error, together with hundreds of other, less helpful errors, when he tried to compile what seemed to be a perfectly fine XAML code. The problems started after he removed all the comments from the source files with a program that he created.

The program simply loads the source file's content, removes the comments, and then writes the updated content back to the file. Here is a naive example to illustrate the problem:

public void ProcessFile(string path)
{
    string originalContent = File.ReadAllText(path);
    string processedContent = Process(originalContent);
    File.WriteAllText(path, processedContent, Encoding.Default);
}

To understand the problem, you should first understand that a compiler is basically just a program that receives a string, processes it, and outputs a new string. The C# compiler is no different, it receives a string that supposedly represents a C# program, validates it, and outputs a string that represents a binary representation of the program, or a list of errors and warnings.

In order for the compiler to interpret the given string correctly, the string format must be agreed upon. The following paragraph is taken from ECMA-334 - C# Language Specification:

A conforming implementation of C# shall interpret characters in conformance with the Unicode Standard, Version 4.0, and ISO/IEC 10646-1. Conforming implementations must accept Unicode source files encoded with the UTF-8 encoding form.

The Visual Studio C# compiler extends the standard and is able to compile source files that are encoded in ASCII, UTF-8 or UTF-32 (those are the ones I checked), but you have to make sure that the source code can be represented in the chosen encoding.

C# code is usually written in English*, so it can be encoded correctly with either one of the above encodings. XAML code, on the other hand, is more likely to contain characters in another language. And if it does, encoding it with the ASCII character set, for example, will cause the compiler to read gibberish.

That is exactly what happened in the above scenario, as the encoding given to the WriteAllText method is Encoding.Default, which returns an encoding for the operating system's current ANSI code page. It is usually not enough if the source code contains non-English characters.

When you are working with text files, make sure to respect the encoding. In the above case, using Encoding.UTF8 fixed the errors.

* You can write perfectly valid c# programs in your own language. Try it.

Oct
25
2012
.NET // C# // WPF

WPF Command Confirmation

In the last post, I introduced you to my DynamicGridFormationBehavior, which gives you the ability to dynamically change a grid's formation, using only Xaml. In this post, I want to introduce you to another behavior, called ConfirmationBehavior.

First let's set the context. Assume that we have an application that handles customers' information, and allows CRUD operations on it. The client asked that before any critical operation on the data (deleting a customer for example), a confirmation message will appear.

If you're following the MVVM pattern in your WPF applications (and you should), you will probably end up with a ViewModel with an ICommand to handle the delete request, and a View with a button which will be bound to the command.

public class CustomerViewModel : NotificationObject
{
	...
	public DelegateCommand DeleteCommand { get; private set; }
	...
}
<Button Content="Delete" Command="{Binding DeleteCommand}"/>

But what about the confirmation? Should it be part of the ViewModel, or part of the View's code-behind?

Putting the confirmation code inside the ViewModel will sacrifice its testability, since the ViewModel will explicitly call MessageBox.Show (or some other alerts-related UI), preventing us from easily writing automatic unit tests for it. Furthermore, placing a UI specific code inside the ViewModel is a violation of the SRP principle.

Putting the confirmation code inside the View's code-behind will not only sacrifice the testability, but also the maintainability of the application, since we will have to duplicate the entire confirmation code over and over again for each button that invokes a command that needs to be confirmed.

Enter ConfirmationBehavior

By encapsulating the confirmation code into a behavior, our code will be testable, since the ViewModel will not contain any UI-related code, and maintainable, since the application's layers will be clearly separated, and the behavior will be reusable.

Let's take a look at the behavior's implementation:

public class ConfirmationBehavior<T> : Behavior<T> where T : ButtonBase
{
	public static readonly DependencyProperty MessageProperty =
		DependencyProperty.Register("Message", typeof (string), typeof (ConfirmationBehavior<T>));

	public string Message
	{
		get { return (string) GetValue(MessageProperty); }
		set { SetValue(MessageProperty, value); }
	}

	public static readonly DependencyProperty CaptionProperty =
		DependencyProperty.Register("Caption", typeof (string), typeof (ConfirmationBehavior<T>));

	public string Caption
	{
		get { return (string) GetValue(CaptionProperty); }
		set { SetValue(CaptionProperty, value); }
	}

	public static readonly DependencyProperty CommandProperty =
		DependencyProperty.Register("Command", typeof (ICommand), typeof (ConfirmationBehavior<T>));

	public ICommand Command
	{
		get { return (ICommand) GetValue(CommandProperty); }
		set { SetValue(CommandProperty, value); }
	}

	public static readonly DependencyProperty CommandParameterProperty =
		DependencyProperty.Register("CommandParameter", typeof (object), typeof (ConfirmationBehavior<T>));

	public object CommandParameter
	{
		get { return GetValue(CommandParameterProperty); }
		set { SetValue(CommandParameterProperty, value); }
	}

	protected override void OnAttached()
	{
		base.OnAttached();
		AssociatedObject.Click += OnButtonClick;
	}

	protected override void OnDetaching()
	{
		base.OnDetaching();
		AssociatedObject.Click -= OnButtonClick;
	}

	private void OnButtonClick(object sender, RoutedEventArgs e)
	{
		if (Command == null || !Command.CanExecute(CommandParameter))
			return;

		if (ShouldConfirm())
		{
			MessageBoxResult result = MessageBox.Show(Message, Caption, MessageBoxButton.YesNo,
													  MessageBoxImage.Question);
			if (result == MessageBoxResult.Yes)
				OnConfirmed();
			else
				OnNotConfirmed();
		}
		else
		{
			OnConfirmed();
		}
	}

	protected virtual bool ShouldConfirm()
	{
		return true;
	}

	protected virtual void OnConfirmed()
	{
		Command.Execute(CommandParameter);
	}

	protected virtual void OnNotConfirmed() { }
}

public class ConfirmationBehavior : ConfirmationBehavior<ButtonBase>
{	
}

public class ToggleConfirmationBehavior : ConfirmationBehavior<ToggleButton>
{
	protected override bool ShouldConfirm()
	{
		return AssociatedObject.IsChecked == true;
	}

	protected override void OnNotConfirmed()
	{
		AssociatedObject.IsChecked = false;
	}
}

Please note the following:

  • The generic type parameter enables us to inherit and customize the behavior for more specific types (like ToggleButton, as you can see above).
  • The behavior allows us to customize the message and caption of the confirmation.
  • Currently, the behavior is using System.Windows.MessageBox, which is impossible to style. You can change it to use a different control if you wish (like the one in the Extended WPF Toolkit).
  • The non-generic ConfirmationBehavior is there just because not all Xaml schemas have a support for generics.

And the usage:

<Button Content="Delete">
	<i:Interaction.Behaviors>
		<behaviors:ConfirmationBehavior
			Message="Are You Sure?"
			Caption="Please Confirm..."
			Command="{Binding DeleteCommand}">
		</behaviors:ConfirmationBehavior>
	</i:Interaction.Behaviors>
</Button>

As you can see, by using the behavior, we kept our ViewModel clean and made our intentions clear for anyone who is reading the Xaml.

The code is available on GitHub, as part of my WPFUtils project.

Oct
7
2012

Intern Pool Improvements Between Various .NET Framework Versions

As you probably know, .NET supports string interning for better memory usage of .NET applications. String literals are automatically interned by the runtime, while any other string can be interned by an explicit call to String.Intern. I will not go into details regarding string interning, if you are not familiar with the concept, you can get started by reading the MSDN documentation for the String.Intern method.

In this post, I would like to write about one of the implementation details of the .NET intern pool, specifically, where it is stored and how the storage strategy was changed between recent .NET framework versions.

The following code is a portion from a simple console application that loops endlessly, asks the user how many strings to intern, and interns the requested amount of unique strings (please ignore the possible overflow and other possible bugs, it is just a quick sketch). The application is compiled for framework 4.5, Any CPU (prefer 32 bit is not checked) and is run on a 64bit machine.

public static void Main(string[] args)
{
    int iterationCount = 0;

    do
    {
        int numberOfStringsToIntern = ReadUserInput();

        Console.WriteLine("Interning {0} Strings", numberOfStringsToIntern);
        string stringPrefix = String.Format("Iteration {0}", ++iterationCount);
        Intern(stringPrefix, numberOfStringsToIntern);

    } while (true);
}

private static void Intern(string stringPrefix, int numberOfStringsToIntern)
{
    for (int stringIndex = 0; stringIndex < numberOfStringsToIntern; ++stringIndex)
    {
        string str = String.Format("{0} - {1}", stringPrefix, stringIndex);
        String.Intern(str);
    }
}

To see what happens when a string is interned, we will launch the application under WinDbg, and will place a breakpoint just before the call to String.Intern (line 21 above).

0:000> .loadby sos clr
0:000> !bpmd Program.cs:48
Found 1 methods in module 000007fbdcc02f90...
MethodDesc = 000007fbdcc03938
Adding pending breakpoints...
0:000> g

When the debugger stops, the str variable should be on the stack, let's find it and inspect who is holding a reference to it.

0:000> !dso
OS Thread Id: 0xdd8 (0)
RSP/REG          Object           Name
rax              000000e78ca47660 System.String    Iteration 1 - 0
rbx              000000e78ca475c8 System.String    {0} - {1}
rdx              000000e78ca45540 System.Text.StringBuilder
rbp              000000e78ca47598 System.String    Iteration 1
000000E78AA2E9B8 000000e78ca47450 System.Int32
000000E78AA2E9D8 000000e78ca47450 System.Int32
000000E78AA2E9E0 000000e78ca42de8 System.String    Iteration {0}
000000E78AA2E9F0 000000e78ca47598 System.String    Iteration 1
000000E78AA2EA50 000000e78ca42d80 System.Object[]    (System.String[])
000000E78AA2EB88 000000e78ca42d80 System.Object[]    (System.String[])
000000E78AA2ECA8 000000e78ca42d80 System.Object[]    (System.String[])
000000E78AA2ECB0 000000e78ca42208 System.Security.Policy.Evidence
000000E78AA2EE68 000000e78ca42d80 System.Object[]    (System.String[])

0:000> !gcroot 000000e78ca47660
Found 0 unique roots (run '!GCRoot -all' to see all roots).

As we can see, prior to being interned, the string has no other roots except the rax register, and will be collected on the first garbage collection that will take place after the return from the method. Inspecting the roots again, after the call to String.Intern, will produce the following output:

0:005> !gcroot 000000e78ca47660
HandleTable:
    000000e78ab817e8 (pinned handle)
    -> 000000e79ca43238 System.Object[]
    -> 000000e78ca47660 System.String

Found 1 unique roots (run '!GCRoot -all' to see all roots).

This time, the string is being referenced by an array of objects. What other data this array contains?

0:005> !da -details -nofields 000000e79ca43238
Name:        System.Object[]
MethodTable: 000007fc3b48f1b8
EEClass:     000007fc3aec1858
Size:        1056(0x420) bytes
Array:       Rank 1, Number of elements 128, Type CLASS
Element Methodtable: 000007fc3b4ab4c0
[0] 000000e78ca41420
    Name:        System.String
    MethodTable: 000007fc3b4aaee0
    EEClass:     000007fc3ae13720
    Size:        26(0x1a) bytes
    File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
    String:              
[1] 000000e78ca42da0
    Name:        System.String
    MethodTable: 000007fc3b4aaee0
    EEClass:     000007fc3ae13720
    Size:        68(0x44) bytes
    File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
    String:          Interning {0} Strings    
[2] 000000e78ca42de8
    Name:        System.String
    MethodTable: 000007fc3b4aaee0
    EEClass:     000007fc3ae13720
    Size:        52(0x34) bytes
    File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
    String:          Iteration {0}    
[3] 000000e78ca42ee0
    Name:        System.String
    MethodTable: 000007fc3b4aaee0
    EEClass:     000007fc3ae13720
    Size:        138(0x8a) bytes
    File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
    String:          How many strings do you want to intern (Ctrl+C To Exit)?    
[4] 000000e78ca475c8
    Name:        System.String
    MethodTable: 000007fc3b4aaee0
    EEClass:     000007fc3ae13720
    Size:        44(0x2c) bytes
    File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
    String:          {0} - {1}    
[5] 000000e78ca47660
    Name:        System.String
    MethodTable: 000007fc3b4aaee0
    EEClass:     000007fc3ae13720
    Size:        56(0x38) bytes
    File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
    String:          Iteration 1 - 0    
[6] null
[7] null
...
[126] null
[127] null

By inspecting the content of the array, we can clearly see that it can hold up to 128 elements and it currently contains all the interned strings of our application. Element 0 is String.Empty, elements 1-4 are the literal strings of the application, that were automatically interned by the runtime, and element 5 is the newly interned string. The array at which we are looking is actually a part of the intern pool. Where is it stored?

0:005> !gcwhere 000000e79ca43238
Address    Gen   Heap   segment    begin      allocated   size
000000e79ca43238   3      0     000000e79ca40000   000000e79ca41000   000000e79ca49638    0x420(1056)

0:005> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x000000e78ca41030
generation 1 starts at 0x000000e78ca41018
generation 2 starts at 0x000000e78ca41000
ephemeral segment allocation context: none
 segment     begin allocated  size
000000e78ca40000  000000e78ca41000  000000e78ca47fe8  0x6fe8(28648)
Large object heap starts at 0x000000e79ca41000
 segment     begin allocated  size
000000e79ca40000  000000e79ca41000  000000e79ca49638  0x8638(34360)
Total Size:              Size: 0xf620 (63008) bytes.
------------------------------
GC Heap Size:            Size: 0xf620 (63008) bytes.

0:005> !dumpheap 000000e79ca41000  000000e79ca49638  
         Address               MT     Size
000000e79ca41000 000000e78abe9e80       24 Free
000000e79ca41018 000007fc3b48f1b8     8736     
000000e79ca43238 000007fc3b48f1b8     1056     
000000e79ca43658 000007fc3b48f1b8     8192     
000000e79ca45658 000007fc3b48f1b8    16352     

Statistics:
              MT    Count    TotalSize Class Name
000000e78abe9e80        1           24      Free
000007fc3b48f1b8        4        34336 System.Object[]
Total 5 objects

As we can see in the above output, the array is stored in the Large Object Heap (we can see it by looking at its address, which is within the bounds of the LOH). How is it possible, given that the minimum allowed size is 85000 bytes? It turns out that the characteristics of the LOH (no compaction, collected only in full GC), makes it a perfect place for the runtime to store some of its frequently-used, long-lived objects, including the intern pool. (From the above output, you can see that there are 3 more arrays, stored there by the runtime, you can dump them to see the various objects they contain).

A quick summary before moving on, to the more interesting parts:

  • After a string is interned, it is being referenced by a special array, to prevent it from being garbage collected.
  • This array is pinned by the runtime, and will probably live for the entire lifetime of the application.
  • Because of the above, the ideal place for it to be allocated is on the LOH.
  • This array can hold up to 128 elements.

What happens when more than 128 strings are interned? It depends in which .NET Framework we are using. To emphasize the differences between the different .NET framework versions, I used the above application, to intern an increasing amount of strings, and check the state of the LOH after each step.

Intern Pool in .NET 3.5

The following is a snapshot of the LOH before any explicit interning was made:

0:003> .loadby sos mscorwks
0:003> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x0000000002881030
generation 1 starts at 0x0000000002881018
generation 2 starts at 0x0000000002881000
ephemeral segment allocation context: none
         segment            begin         allocated             size
0000000002880000 0000000002881000  0000000002935fe8 0x00000000000b4fe8(741352)
Large object heap starts at 0x0000000012881000
         segment            begin         allocated             size
0000000012880000 0000000012881000  0000000012887048 0x0000000000006048(24648)
Total Size           0xbb030(766000)
------------------------------
GC Heap Size           0xbb030(766000)
0:003> !dumpheap 0000000012881000  0000000012887048
         Address               MT     Size
0000000012881000 000000000043c000       24 Free
0000000012881018 000007feeaca5a08     8192     
0000000012883018 000000000043c000       24 Free
0000000012883030 000007feeaca5a08     1056     
0000000012883450 000000000043c000     7136 Free
0000000012885030 000007feeaca5a08     8192     
0000000012887030 000000000043c000       24 Free
total 7 objects
Statistics:
              MT    Count    TotalSize Class Name
000000000043c000        4         7208      Free
000007feeaca5a08        3        17440 System.Object[]
Total 7 objects

As we can see, the runtime pre allocated a single, 128 elements, object array (the 1056 bytes object at line 21) to store the interned strings (the other two arrays are the general purpose arrays described above. Notice that the number and size of those arrays is different than in framework 4.5). At this stage, the intern pool's array contains only the 4 literal strings which were automatically interned, and the String.Empty reference.

Let's take another look at the LOH, this time, after interning 200 strings:

0:003> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x0000000002881030
generation 1 starts at 0x0000000002881018
generation 2 starts at 0x0000000002881000
ephemeral segment allocation context: none
         segment            begin         allocated             size
0000000002880000 0000000002881000  0000000002945fe8 0x00000000000c4fe8(806888)
Large object heap starts at 0x0000000012881000
         segment            begin         allocated             size
0000000012880000 0000000012881000  0000000012889048 0x0000000000008048(32840)
Total Size           0xcd030(839728)
------------------------------
GC Heap Size           0xcd030(839728)
0:003> !dumpheap 0000000012881000  0000000012889048
         Address               MT     Size
0000000012881000 000000000043c000       24 Free
0000000012881018 000007feeaca5a08     8192     
0000000012883018 000000000043c000       24 Free
0000000012883030 000007feeaca5a08     1056     
0000000012883450 000000000043c000     7136 Free
0000000012885030 000007feeaca5a08     8192     
0000000012887030 000000000043c000       24 Free
0000000012887048 000007feeaca5a08     1056     
0000000012887468 000000000043c000     7136 Free
total 9 objects
Statistics:
              MT    Count    TotalSize Class Name
000000000043c000        5        14344      Free
000007feeaca5a08        4        18496 System.Object[]
Total 9 objects

After running out of space in the original 128 elements array, the runtime allocated another array to hold additional 128 interned strings (line 24). The array was allocated as part of an 8KB block of memory (memory alignment, I guess), the extra 7136 bytes were marked as free.

Finally, let's take a look at the LOH after interning another 4000 strings:

0:003> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x0000000002881030
generation 1 starts at 0x0000000002881018
generation 2 starts at 0x0000000002881000
ephemeral segment allocation context: none
         segment            begin         allocated             size
0000000002880000 0000000002881000  0000000002a53fe8 0x00000000001d2fe8(1912808)
Large object heap starts at 0x0000000012881000
         segment            begin         allocated             size
0000000012880000 0000000012881000  00000000128c5fe8 0x0000000000044fe8(282600)
Total Size          0x217fd0(2195408)
------------------------------
GC Heap Size          0x217fd0(2195408)
0:003> !dumpheap 0000000012881000  00000000128c5fe8
         Address               MT     Size
0000000012881000 000000000043c000       24 Free
0000000012881018 000007feeaca5a08     8192     
0000000012883018 000000000043c000       24 Free
0000000012883030 000007feeaca5a08     1056     
0000000012883450 000000000043c000     7136 Free
0000000012885030 000007feeaca5a08     8192     
0000000012887030 000000000043c000       24 Free
0000000012887048 000007feeaca5a08     1056     
0000000012887468 000000000043c000     7136 Free
0000000012889048 000007feeaca5a08     1056     
0000000012889468 000000000043c000     7136 Free
000000001288b048 000007feeaca5a08     1056     
000000001288b468 000000000043c000     7136 Free
…
00000000128bffe8 000007feeaca5a08     1056     
00000000128c0408 000000000043c000     7136 Free
00000000128c1fe8 000007feeaca5a08     1056     
00000000128c2408 000000000043c000     7136 Free
00000000128c3fe8 000007feeaca5a08     1056     
00000000128c4408 000000000043c000     7136 Free
total 71 objects
Statistics:
              MT    Count    TotalSize Class Name
000007feeaca5a08       35        51232 System.Object[]
000000000043c000       36       231368      Free
Total 71 objects

Now it's getting interesting! Whenever the intern pool runs out of space, another 128 elements array is allocated, to store the additional strings. As before, we can see that a larger memory block is allocated, exactly 8KB in this case, from which only 1056 bytes are used. The additional 7136 bytes are marked as free, and will forever remain free, because no other object will ever be able to fit inside, as only objects larger than 85000 bytes are allocated on the LOH. For each 128 interned strings, we lose 7136 bytes of memory. That’s 100MB for under 2,000,000 strings.

I can think of more than one scenario in which an application will have more than that number of interned strings. For some applications, string literals alone can take thousands of places in the pool. It's a shame that all this memory will go to waste. Luckily, as we will see, this is no longer an issue on .NET framework 4.0.

Intern Pool in .NET 4.0

The following is a snapshot of the LOH before any explicit interning was made:

0:004> .loadby sos clr
0:004> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x00000000023e1030
generation 1 starts at 0x00000000023e1018
generation 2 starts at 0x00000000023e1000
ephemeral segment allocation context: none
         segment             begin         allocated  size
00000000023e0000  00000000023e1000  00000000023f3fe8  0x12fe8(77800)
Large object heap starts at 0x00000000123e1000
         segment             begin         allocated  size
00000000123e0000  00000000123e1000  00000000123e7048  0x6048(24648)
Total Size:              Size: 0x19030 (102448) bytes.
------------------------------
GC Heap Size:    Size: 0x19030 (102448) bytes.
0:004> !dumpheap 00000000123e1000  00000000123e7048
         Address               MT     Size
00000000123e1000 000000000010bab0       24 Free
00000000123e1018 000007feed12ae88     8192     
00000000123e3018 000000000010bab0       24 Free
00000000123e3030 000007feed12ae88     1056     
00000000123e3450 000000000010bab0     7136 Free
00000000123e5030 000007feed12ae88     8192     
00000000123e7030 000000000010bab0       24 Free
total 0 objects
Statistics:
              MT    Count    TotalSize Class Name
000000000010bab0        4         7208      Free
000007feed12ae88        3        17440 System.Object[]
Total 7 objects

The initial layout of the LOH stayed the same as it was on .NET framework 3.5. Let's intern 200 strings and see what happens:

0:007> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x00000000023e1030
generation 1 starts at 0x00000000023e1018
generation 2 starts at 0x00000000023e1000
ephemeral segment allocation context: none
         segment             begin         allocated  size
00000000023e0000  00000000023e1000  0000000002403fe8  0x22fe8(143336)
Large object heap starts at 0x00000000123e1000
         segment             begin         allocated  size
00000000123e0000  00000000123e1000  00000000123e9048  0x8048(32840)
Total Size:              Size: 0x2b030 (176176) bytes.
------------------------------
GC Heap Size:    Size: 0x2b030 (176176) bytes.
0:007> !dumpheap 00000000123e1000  00000000123e9048
         Address               MT     Size
00000000123e1000 000000000010bab0       24 Free
00000000123e1018 000007feed12ae88     8192     
00000000123e3018 000000000010bab0       24 Free
00000000123e3030 000007feed12ae88     1056     
00000000123e3450 000000000010bab0     7136 Free
00000000123e5030 000007feed12ae88     8192     
00000000123e7030 000000000010bab0       24 Free
00000000123e7048 000007feed12ae88     2080     
00000000123e7868 000000000010bab0     6112 Free
total 0 objects
Statistics:
              MT    Count    TotalSize Class Name
000000000010bab0        5        13320      Free
000007feed12ae88        4        19520 System.Object[]
Total 9 objects

Unlike in .NET framework 3.5, after running out of space in the initial, 128 elements array (line 20), the runtime has allocated an additional array (line 24) with 256 elements, double the size of the first one. Let's take a look at the LOH after interning another 40000 strings:

0:004> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x0000000002673778
generation 1 starts at 0x000000000248e028
generation 2 starts at 0x00000000023e1000
ephemeral segment allocation context: none
         segment             begin         allocated  size
00000000023e0000  00000000023e1000  0000000002a39790  0x658790(6653840)
Large object heap starts at 0x00000000123e1000
         segment             begin         allocated  size
00000000123e0000  00000000123e1000  0000000012469170  0x88170(557424)
Total Size:              Size: 0x6e0900 (7211264) bytes.
------------------------------
GC Heap Size:    Size: 0x6e0900 (7211264) bytes.
0:004> !dumpheap 00000000123e1000  0000000012469170
         Address               MT     Size
00000000123e1000 000000000010bab0       24 Free
00000000123e1018 000007feed12ae88     8192     
00000000123e3018 000000000010bab0       24 Free
00000000123e3030 000007feed12ae88     1056     
00000000123e3450 000000000010bab0     7136 Free
00000000123e5030 000007feed12ae88     8192     
00000000123e7030 000000000010bab0       24 Free
00000000123e7048 000007feed12ae88     2080     
00000000123e7868 000000000010bab0     6112 Free
00000000123e9048 000007feed12ae88     4128     
00000000123ea068 000000000010bab0     4064 Free
00000000123eb048 000007feed12ae88     8224     
00000000123ed068 000000000010bab0       24 Free
00000000123ed080 000007feed12ae88    16416     
00000000123f10a0 000000000010bab0       24 Free
00000000123f10b8 000007feed12ae88    32800     
00000000123f90d8 000000000010bab0       24 Free
00000000123f90f0 000007feed12ae88    65568     
0000000012409110 000000000010bab0       24 Free
0000000012409128 000007feed12ae88   131072     
0000000012429128 000000000010bab0       24 Free
0000000012429140 000007feed12ae88   131072     
0000000012449140 000000000010bab0       24 Free
0000000012449158 000007feed12ae88   131072     
0000000012469158 000000000010bab0       24 Free
total 0 objects
Statistics:
              MT    Count    TotalSize Class Name
000000000010bab0       13        17552      Free
000007feed12ae88       12       539872 System.Object[]
Total 25 objects

The output confirms that the intern pool allocation algorithm was changed to address the fragmentation problem that was in .NET framework 3.5 by doubling the size of each additional array (up to 16384 elements), and by that, reducing the amount of wasted memory.

It seems that the memory is still allocated in blocks of 8KB, which is not very economical for the small arrays. After the first array we have 7136 free bytes, after the second we have 6112 free bytes and after the third we have 4064 free bytes. All of that memory will go to waste.

One more thing that we can see is those 24 byte blocks of free memory that acts as a minimum boundary between each two objects allocated on the LOH.

Intern Pool in .NET 4.5

First thing first, the LOH before any explicit interning was made:

0:004> .loadby sos clr
0:004> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x000000db02821030
generation 1 starts at 0x000000db02821018
generation 2 starts at 0x000000db02821000
ephemeral segment allocation context: none
 segment     begin allocated  size
000000db02820000  000000db02821000  000000db02827fe8  0x6fe8(28648)
Large object heap starts at 0x000000db12821000
 segment     begin allocated  size
000000db12820000  000000db12821000  000000db12829638  0x8638(34360)
Total Size:              Size: 0xf620 (63008) bytes.
------------------------------
GC Heap Size:            Size: 0xf620 (63008) bytes.
0:004> !dumpheap 000000db12821000  000000db12829638
         Address               MT     Size
000000db12821000 000000db00bea240       24 Free
000000db12821018 000007fc3b48f1b8     8736     
000000db12823238 000007fc3b48f1b8     1056     
000000db12823658 000007fc3b48f1b8     8192     
000000db12825658 000007fc3b48f1b8    16352     

Statistics:
              MT    Count    TotalSize Class Name
000000db00bea240        1           24      Free
000007fc3b48f1b8        4        34336 System.Object[]
Total 5 objects

Nothing has changed regarding the initial allocation of the intern pool. Like in the two previous .NET framework versions, the initial array can hold up to 128 strings. Two other things were changed. The first is the size and amount of general purpose arrays and the second is that we no longer see the 24 bytes of free space between each two elements. Let's take a final look at the LOH, after interning 40000 strings:

0:003> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x000000db0299aba8
generation 1 starts at 0x000000db02821018
generation 2 starts at 0x000000db02821000
ephemeral segment allocation context: none
 segment     begin allocated  size
000000db02820000  000000db02821000  000000db02eb5fe8  0x694fe8(6901736)
Large object heap starts at 0x000000db12821000
 segment     begin allocated  size
000000db12820000  000000db12821000  000000db128a8ef8  0x87ef8(556792)
Total Size:              Size: 0x71cee0 (7458528) bytes.
------------------------------
GC Heap Size:            Size: 0x71cee0 (7458528) bytes.
0:003> !dumpheap 000000db12821000  000000db128a8ef8
         Address               MT     Size
000000db12821000 000000db00bea240       24 Free
000000db12821018 000007fc3b48f1b8     8736     
000000db12823238 000007fc3b48f1b8     1056     
000000db12823658 000007fc3b48f1b8     8192     
000000db12825658 000007fc3b48f1b8    16352     
000000db12829638 000007fc3b48f1b8     2080     
000000db12829e58 000007fc3b48f1b8     4128     
000000db1282ae78 000007fc3b48f1b8     8224     
000000db1282ce98 000007fc3b48f1b8    16416     
000000db12830eb8 000007fc3b48f1b8    32800     
000000db12838ed8 000007fc3b48f1b8    65568     
000000db12848ef8 000007fc3b48f1b8   131072     
000000db12868ef8 000007fc3b48f1b8   131072     
000000db12888ef8 000007fc3b48f1b8   131072     

Statistics:
              MT    Count    TotalSize Class Name
000000db00bea240        1           24      Free
000007fc3b48f1b8       13       556768 System.Object[]
Total 14 objects

Although not directly related to the intern pool allocation algorithm, we can clearly see that additional memory was saved by eliminating the 24 bytes of free space between each two elements. In fact, there is no free space at all between the elements. Maybe that is one of the improvements mentioned here and here.

Nov
1
2010

WinDbg, SOS and the Data Access Layer

Did you ever get the following message while trying to debug a managed application's dump file?

"Failed to load data access DLL…"

In this post I will explain why and will propose a solution.

In order for SOS to work properly, it needs to know the internal data structures of the CLR. Since those internal structures may vary between different .NET versions, Microsoft decided to write a mediator, through which SOS will access them. This mediator comes in the form of a DLL named mscordacwks.dll, which is distributed with every .NET version.

SOS prints the above error message because the .NET framework on the machine we are currently debugging on is different than the one on the machine on which the memory dump was taken, which means that the existing mscordacwks.dll does not match the dump's mscorwks.dll, and without it, SOS cannot understand the data structures.

To fix it, we need to know the .NET version of the machine on which the dump was taken. We can check it by executing the following command in WinDbg:

lm v m mscorwks

Now, we need to get the matching mscordacwks.dll. If we have an access to the machine on which the dump was taken, we can just take it from there, under [Windows Installation Dir]\Microsoft.NET\Framework\[Version]\.

When the matching file, is on the machine on which we are debugging the dump file, we need to direct WinDbg to it. We can do it by doing the following:

  1. Changing the name of the matching mscordacwks.dll to the following format: mscordacwks_[architecture]_[architecture]_[version].dll Where [architecture] is x86 or amd64, for example: mscordacwks_x86_x86_2.0.50727.3603.dll
  2. Executing the following command in WinDbg:
.cordll –sd –u –lp [Path To File] –l

Where:

  • -sd : instructs the debugger to look for the DLL by its full name, as described above.
  • -u : unloads the currently loaded mscordacwks.dll
  • -lp : the full path to the DLL
  • -l : loads the new mscordacwks.dll.

That’s it. SOS should work perfectly from now on.

May
12
2010
.NET // C#

C# Contravariance Example

Take a look at the following types:

public interface IDomainObject 
{
	string Id { get; }
}

public class Customer : IDomainObject { … }

public class ShoppingCart : IDomainObject { … }

public class DomainObjectEqualityComparer : IEqualityComparer<IDomainObject> 
{
	public bool Equals(IDomainObject first, IDomainObject second)
	{
		return Equals(first.Id, second.Id);
	}
	public int GetHashCode (IDomainObject obj)
	{
		return obj.Id.GetHashCode();
	}
}

And the following usage:

public bool IsCustomerExist(Customer customer)
{
	// m_customers is a member of type IList<Customer>
	return m_customers.Contains(customer, new DomainObjectEqualityComparer());
}

Trying to compile it for any .NET Framework prior to 4.0, will fail because the Contains method expects a parameter of type IEqualityComparer<Customer> and not of type IEqualityComparer<IDomainObject>. The fact that we can pass a Customer object to any method that expects IDomainObject, does not mean that we can do the same for types that are using those types as type parameters. Otherwise, the following code would be valid:

IList<Customer> customers = new List<Customer>();
customers.Add(new Customer());
IList<IDomainObject> domainObjects = customers;
domainObjecs.Add(new ShoppingCart());

The above code will fail at runtime, which contradicts the whole point of using generics.

In C# 4.0, we can define generic type parameters as covariant or contra variant, A feature that was already in the CLR since version 2.0. Take a look at how IEqualityComparer is defined in C# 4.0:

public interface IEqualityComparer<in T>

The in keyword marks the generic type parameter as contra variant, which enables us to pass IEqualityComparer<IDomainObject> to methods that expects a parameter of type IEqualityComparer<Customer>. Therefore, the above code compiles in .NET .4.0 without any change. You can read more about covariance and contra variance here.

In order to compile the above code in .NET 3.5, we need to do the following changes:

public class DomainObjectComparer<T> : IEqualityComparer<T> where T: IDomainObject
{
	public  bool Equals (T first, T second)
	{
		return Equals(first.Id, second.Id); 
	}
	
	public int GetHashCode(T obj)
	{
		return obj.Id.GetHashCode();
	}
}

We made the class generic with a type parameter that is constrained to be of type IDomainObject. Now we can use it like so:

m_customers.Contains(customer, new DomainObjectEqualityComparer<Customer>());
Jan
25
2010

Distributing Your Documentation

Whenever we are using Xml documentation (by using ///), Visual Studio's Intellisense will use this information for showing the method's documentation when it is being hovered, or the method's parameters information as they are being typed.

The thing is that, by default, Visual Studio will be able to do it only for types that are declared in the same project or in another project in the same solution. That is because the documentation is not saved as part of the assembly.

In order to make it possible for Visual Studio to show this information when a type is being used in another solution, we need to generate an XML file that contains the documentation, and distribute it along with the assembly. We can do it by opening the project's properties, navigating to the Build tab, and checking the XML Documentation File checkbox. This will instruct the compiler to create an XML documentation file on each build, a file that we should distribute along with the assembly.

Be advised that, after checking that option, the compiler will issue a warning for each public member that is not documented. Please, do not fix those warnings by writing meaningless comments for each and every public member. Lack of documentation is better than a meaningless one. You can suppress this warning for a specific member by adding #pragma warning disable 1591. You can also globally suppress it by adding its number (1591) to the Suppress Warnings option in the project's properties.

Jan
14
2010

No JIT for You

As you know, C# code is not compiled directly into machine code. Rather, it's compiled into a platform agnostic IL, which is then compiled at runtime into the machine code of the platform on which it is being executed. This process is called Just in Time Compilation (JIT), and it is what making it possible for us to compile our code once, and run it on every platform that can run the .NET runtime.

So, when exactly does the JIT compiler compiles our code? The answer is "Just in Time", which means, just before the first time we use it. The JIT compilation is done per method. Each method is compiled just before it is being called for the first time.

The following application contains a class named SomeClass which contains a method named DoSomething. I stopped the debugger before the first call for the method. We can see that it is not compiled yet:

0:003> .loadby sos mscorwks
0:003> !name2ee NGenTest.exe NGenTest.SomeClass.DoSomething
Module: 00462f2c (NGenTest.exe)
Token: 0x06000005
MethodDesc: 00463354
Name: NGenTest.SomeClass.DoSomething()
Not JITTED yet. Use !bpmd -md 00463354 to break on run.

If we stop the debugger again, after the method was called, we can see that it is compiled. We can also see the address of the compiled code:

0:003> !name2ee NGenTest.exe NGenTest.SomeClass.DoSomething
Module: 00462f2c (NGenTest.exe)
Token: 0x06000005
MethodDesc: 00463354
Name: NGenTest.SomeClass.DoSomething()
JITTED Code Address: 00c50190

We can look at the generated machine code by using the !u command:

0:003> !u 00c50190
Normal JIT generated code
NGenTest.SomeClass.DoSomething()
Begin 00c50190, size 27
00c50190 55             	push    ebp
00c50191 8bec            	mov     ebp,esp
00c50193 50              	push    eax
00c50194 894dfc         	mov     dword ptr [ebp-4],ecx
00c50197 833de430460000 	cmp     dword ptr ds:[4630E4h],0
00c5019e 7405           	je      00c501a5
00c501a0 e8a4a54779      	call    mscorwks!CorLaunchApplication+0xec4b (7a0ca749) (JitHelp: CORINFO_HELP_DBG_IS_JUST_MY_CODE)
00c501a5 90              	nop
00c501a6 8b0d38203d02    	mov     ecx,dword ptr ds:[23D2038h] ("Done!")
00c501ac e86737b478      	call    mscorlib_ni+0x6d3918 (79793918) (System.Console.WriteLine(System.String), mdToken: 060007c8)
00c501b1 90             	        nop
00c501b2 90              	nop
00c501b3 8be5           	mov     esp,ebp
00c501b5 5d              	pop     ebp
00c501b6 c3              	        ret

We can see that the DoSomething method just prints the word "Done!" to the screen.

As you understand, JIT compiling each method just before its first use, may have some adverse effect on the performance of the application. Basically, the JIT compilation is very efficient and usually we do not need to worry about it. But as always, there are special cases, and for those cases, in which we want to prevent the performance drop of the first method call, Microsoft has a solution.

As I said at the beginning, the main advantage of JIT compiling is the ability to compile our code just once and run it on multiple platforms. But what about after the application is deployed on a specific machine? Do we really need our code to be JIT compiled over and over again each time it is being run?

The answer in no. we can skip JIT compilation by pre compiling the application for a specific platform. We can do it by using NGen.exe (Native Image Generation), a utility that is shipped as part of the .NET Framework SDK. The following command will create a native image of the NGenTest.exe assembly for the platform on which it is executed:

ngen.exe install NGenTest.exe

After executing the above command, a new image will be created, named NGenTest.ni.exe (ni stands for Native Image), which will be placed in the GAC under a special folder that contains all the native images. Now, whenever the application will be executed, in addition to loading NGenTest.exe, the CLR will automatically load the corresponding native image and will redirect all the method implementations to it.

By running the application under the debugger, we can see that the native image was loaded automatically by the CLR:

0:003> lm
start    end        module name
00400000 00408000   NGenTest C 
30000000 30008000   NGenTest_ni C
…

We can also see where it was loaded from:

0:003> lmv
…
30000000 30008000   NGenTest_ni C 
    Loaded symbol image file: C:\WINNT\assembly\NativeImages_v2.0.50727_32\NGenTest\17757c9513519b4c559b3202e90ef380\NGenTest.ni.exe
    Image path: C:\WINNT\assembly\NativeImages_v2.0.50727_32\NGenTest\17757c9513519b4c559b3202e90ef380\NGenTest.ni.exe
    Image name: NGenTest.ni.exe
…

This time, we can see that the method is compiled even before it was called for the first time:

0:003> !name2ee NGenTest.exe NGenTest.SomeClass.DoSomething
Module: 30001000 (NGenTest.exe)
Token: 0x06000005
MethodDesc: 30001590
Name: NGenTest.SomeClass.DoSomething()
JITTED Code Address: 300052ac

The code starts at address 300052ac, which, as expected, is within the memory bounds of the native image (30000000 – 30008000).

If you will scroll up and look closely at the output of the !u command, you will be able to see that the call to System.Console.WriteLine is being made on an address which resides in mscorlib.ni.dll, which means that Microsoft themselves are pre compiling some of the .NET framework's assemblies.

Final note, remember that the JIT compiler should be very efficient. Trying to improve the performance of your application by pre compiling it, should be one of your last steps.

About Moshe

Moshe Levi has over 10 years of rich experience building various kinds of applications using C#, C++, and Java for Windows, Linux, and Android. Moshe specializes in WPF, Prism, various IoC frameworks, and NHibernate, as well as in production debugging and performance tuning.

He is currently working as a consultant at Sela, and focused mainly on architecting and developing smart client applications using C#, WPF and Prism.