Windows Process, .Net Application Domain and 2 GB limit on 32-bit Windows

A few weeks ago I heard some comments from a colleague about how .Net applications run and that “all .Net applications run in the same runtime (CLR) so that if you start 10 separate .Net applications, they would share together a single 2 GB limit on Windows 32-bit”. This of course not true and it gave me the idea to blog about the 2GB limit on 32-bit systems, Windows Process, .Net applications and the concept of .Net Application Domain.

2 GB limitation on Windows 32-bit.

32-bit Operating Systems are capped by the number of unique pointers that can exist at a time. On 32-bit processors, only 2^32 distinct addresses can exist. Would all these addresses be used, that would represent 4 GB of memory. On a Windows Operating System the memory address system is not a 1-to-1 relationship to the physical memory of your hardware otherwise you would be stuck with a maximum of 4 GB of addressable memory for the whole machine. This would include all the I/O address space, kernel memory and so leave much less actual memory for programmers to use.

This is why when we talk about memory, it is important to realize the distinction between the physical memory (RAM on the motherboard) and the Virtual Memory accessible through the Virtual Address Space. Note that actually, Virtual Memory is not the same as Virtual Address Space and that there are ways to use Virtual Memory without using the Virtual Address Space. I will nevertheless not go into these details; the important thing to remember is that Windows has a complex memory management system that enables the O.S. to use much more than 4 GB as a whole. The inner workings are not for the faint-hearted and are actually not of interest for most .Net programmers living in the managed world.

Check this blog post for a primer on memory management on Windows Operating System.

When Windows 32 starts a program, a 32 bit process using 32 bit size pointers is created and so the process has a maximum of 4 GB of addressable memory.
Windows will assign to the process a Virtual Address Space of 4 GB (2^32) split in two; 2 GB of user mode virtual address space and 2 GB of kernel mode virtual address space. The user mode virtual address space is the “memory” (read the virtual address space to be correct) available for your program to use.
This 2 GB user mode virtual address space limit is what is commonly called the 2 GB memory limit on Windows 32-bit.

/3 GB switch on 32-bit Windows

The /3GB switch changes the way the 4GB virtual address space is split up. With the /3GB switch, the split is 3GB of user mode virtual address space and 1GB of kernel mode virtual address space. It is nevertheless not recommended to use this option as it can bring unexpected bug from drivers and other kernel-mode processes which might expect to have 2 GB of kernel virtual address space available (not that a driver would ever need 2 GB, just that an older driver might expect to have addresses from 0x80000000 to 0xFFFFFFFF available).
See here and here for other problems that can arise when using the /3GB switch.

AWE

AWE does not give more virtual address space to a process. AWE stands for Address Windowing Extension and is a Microsoft API (Application Programming Interface) that allows a 32-bit software application to access more physical memory that it has virtual address space.
AWE enables programs to reserve physical memory as non-paged memory and then to dynamically map portions of the non-paged memory to the program’s working set of memory. This process enables memory-intensive programs, such as large database systems, to reserve large amounts of physical memory for data without having to be paged in and out of a paging file for usage.
To be clear, AWE can only be available on programs that actually use the AWE API, it is not an OS switch that can be turned on/off on any program.

Windows 64-bit

On windows 64-bit there is not 2 GB limit, the user mode virtual address space limit being 8TB. See here for reference.

Windows Process and Runtime Host

A Windows process is an instance of a program that is executing over the Windows layer. A process contains the executable code and data inside the memory reserved for it by the Operating System. There will be at least one thread executing instructions within the process but more in most cases.

Any program running on Windows is actually working within a process. If you open 2 instances of notepad, you can see that 2 processes running notepad.exe are visible under the Processes tab of the Windows Task Manager.

The concept of a Process exists for two main reasons:

  • To enable multitasking (time sharing), the different processes a CPU is running will have their states changing between running and waiting very quickly and so give the illusion to the end-user that all processes are running in the same time. This brings multitasking as well as scalability.
  • To provide boundaries between running programs so that a process cannot peak into another one and that erroneous code inside a process cannot corrupt areas outside of that process (so that a process cannot crash another one). This is brings security and stability.

The isolation between processes is achieved by making sure that any given unique virtual address space runs exactly into one process and not any other.

Runtime Host

.Net applications are compiled in CIL (Common Intermediate Language, formally called MSIL – Microsoft Intermediate Language), and then are JITed (Just-In-Time compiled) by the CLR (Common Language Runtime) into instructions directly understandable by the CPU (native code).
Here is an illustration of this 2 step compilation process:


This means that .Net applications are not Win32 applications and so cannot be executed directly by the Operating System. As any application running on Windows has to run through a Windows Process, a Windows Process called a Runtime Host will actually execute (host) the .Net Application. The Runtime Host first loads the CLR dll (a native Windows library – unmanaged code) which in turn loads the .Net application (managed code), JIT compiles it and runs it. The process thus effectively transitions the control of running the application from itself to the CLR.

There are 2 types of Runtime Host shipped with the .Net Framework, ASP.NET and Shell. Shell runs all Windows-type applications (Windows Form, Windows Service or Console App).

We can see that this concept actually adds a new layer between the .Net application and the Operating System. This layer, implemented by the CLR, is generically called a Virtual Machine and has OS-like features. It is an abstraction layer between the .Net application and the Operating System. As with Java, this permits any .Net Application to run on any Operating System as long as there is a CLR implemented for that OS.

2 GB limit for .Net applications

As the Runtime Host is a Windows Process, the .Net applications run by a Runtime Host is limited to the 2GB barrier on 32-bit Windows OS. Nevertheless, every Runtime Host has a separate 2 GB virtual address space limit. So would you launch 2 instances of a .Net application, each being a separate process in Task Manager, they would each have 2 GB limit.

.Net Application Domain

An Application Domain is the CLR equivalent of an Operating System’s process. As the Windows OS brings logical and physical isolation between Windows applications through the use of Processes, a single Runtime Host Windows Process can run several isolated .Net applications through the use of Application Domains. As explained before, Windows isolate processes by assigning different virtual memory address space to each process. In the .Net world, the memory is actively managed by the CLR and so the CLR can make sure that memory addresses are not shared between application domains, effectively isolating different Application Domains running in the same Runtime Host.

When a Runtime Host starts a .Net application, the CLR will create a default Application Domain to run the .Net application. As multiple Processes can run on a single OS, multiple Application Domains can run within the same Runtime Host.

An Application Domain is cheaper to create than a Windows Process and has relatively less overhead to maintain. It is thus more efficient to isolate .Net Application through Application Domains rather than Windows Processes. Application Domains are sometimes referenced as lightweight processes but strictly speaking, they are NOT processes.

To summarize, here is a list of advantages of having Application Domains within a Runtime Host Process (which are for most of them similar to the advantages of having Processes within an Operating System):

  • An Application Domain is a more lightweight mean to provide isolation between .Net applications than Processes.
  • A .Net application in an Application Domain can be stopped without affecting the state of another application running in a separate Application Domain.
  • A crash in an Application Domain will not affect other Application Domains neither the Runtime Host Process hosting the Application Domains.
  • Configuration information is part of an Application Domain scope, not the process’ scope.
  • Each Application Domain can have different security access levels assigned to them, all within the same Runtime Host Process.
  • Code in one .Net Application Domain cannot directly access memory in another Application Domain. If two .Net applications need to communicate across Application Domains, they need to use .Net Remoting to do so. In .Net 1.x, this kind of inter-process communication was expensive because the TCP/IP stack needed to be involved. In .Net 2.0, .Net Remoting supports named pipe remoting which is much more efficient. WCF in .Net 3.x has this feature as well.

BizTalk process and Service name relation.

Under Windows, the simplest way to see the CPU usage and Memory usage of a process is by using the Windows Task Manager.

If your BizTalk server contains many BizTalk applications and no performance monitoring system such as WMI installed or configured, a quick way to check which BizTalk process is using the most resource is through the Task Manager.
The only problem with this method is that all you will see under the Task Manager is something like:

Under Windows XP and Windows Server 2003, the Task Manager will show the executable name of the process and the PID (the Process ID – a unique number across all processes) but does not show the Windows Service(s) name that the process is running.

The Windows Services browser (found in the Computer Management application or by running “services.msc”) shows service names:

In the picture above, you can see that I have many BizTalk Windows Services started; each of them being in fact what is called a “BizTalk host”. A BizTalk host is the windows service process that will host 1 or more BizTalk application. As you can see, each BizTalk host is assigned a different Service name – a concatenation of the BizTalk group name and the BizTalk Host name.

To know which BizTalk application uses the most server resource, I need to relate my readings from Task Manager (the process PID) and the Service Name in the services browser. There are 2 ways to discover this relationship; the first is by using a standard command line utility (tasklist) and the second is by downloading a tool (process explorer).

1. Tasklist command.

The simplest way to know which BizTalk host is run by which process is to use the command line utility tasklist.

Tasklist.exe is a command line utility program available in standard for both Windows XP Pro and Windows Server 2003. XP Home seems to not have that utility but this is a non-issue for BizTalkers.
Tasklist displays a list of applications (processes) running on a system. One interesting thing is that it has an option to display the name of the windows services running under each process. Note that some processes, such as svchost.exe, can host more than 1 Windows Service. Svchost is a special process hosting Windows Services that don’t have their own executable host (process). Basically, svchost is used to run Windows Services which are encapsulated as a dll, such as drivers, network management and other basic services.
If a process does not run any Windows Service, such as normal executables, tasklist will display N/A instead of a service name. For Example the process of MS Word, WINWORD, displays N/A for the service name.

Tasklist usage example:

“Tasklist /svc” will display all the processes with the windows services name running in each process (if any).

“tasklist /svc /fi “imagename eq btsntsvc.exe” will display all the BizTalk host processes and the service (host) name running in each process. In my environment I have the following result:

In this way, through the PID, I can relate which process is running which Windows Service (BizTalk host in my instance). So, I can go to Task Manager and see which BizTalk host is consuming the most CPU and memory resource.

2. Process Explorer.

If you don’t like command line tools and prefer to use a Windows application, you can download and install Process Explorer, available for download on Technet.

Process Explorer is some kind of “Task Manager on steroids” which shows you much more information than Task Manager does. For our particular need is able to show what Windows Services is running under each process.

To see the services running under a process, open Process Explorer, find the services.exe node (under which are all processes running Windows Services), locate the BizTalk.exe processes and right click on them, then click “properties” in the context menu and finally click on the “Services” tab; you will see the name of the Windows Service run by that process.

Screenshot of the properties window of a BizTalk process showing the name of the BizTalk Windows Service host running.