Memory limits for a 32-bit .NET application

I’m currently working on an application which is deployed to Windows XP (yes some corporates are still on XP), so whilst I hope this post will be useless soon, I still currently need to worry about memory usage on a 32-bit machine.

Whilst Windows XP has a 4GB memory limit, not all of this is available to your application. An application/process on a 32-bit version of windows has 2GB of available memory to use (if using the /3G switch on Windows Server 2003 then you can get 3GB). You may start to see Out of Memory exceptions (obviously depending upon what you’re trying to allocate and garbage collection etc.) at around 1.2GB.

Whilst this application is currently running on a 32-bit version of Windows it may move to a 64-bit version soon. If it has to remain as a 32-bit application it will have double the amount of memory available. So a 32-bit application on a 64-bit version of Windows will have 4GB available and Out of memory exceptions may occur in the region of 2.8GB memory usage.

Here’s a little bit of code that allows us to get the memory usage for a process

public class MemoryInformation
{
[DllImport(“KERNEL32.DLL”)]
private static extern int OpenProcess(uint dwDesiredAccess,
int bInheritHandle, uint dwProcessId);
[DllImport(“KERNEL32.DLL”)]
private static extern int CloseHandle(int handle);

[StructLayout(LayoutKind.Sequential)]
private class PROCESS_MEMORY_COUNTERS
{
public int cb;
public int PageFaultCount;
public int PeakWorkingSetSize;
public int WorkingSetSize;
public int QuotaPeakPagedPoolUsage;
public int QuotaPagedPoolUsage;
public int QuotaPeakNonPagedPoolUsage;
public int QuotaNonPagedPoolUsage;
public int PagefileUsage;
public int PeakPagefileUsage;
}

[DllImport(“psapi.dll”)]
private static extern int GetProcessMemoryInfo(int hProcess,
[Out] PROCESS_MEMORY_COUNTERS counters, int size);

public static long GetMemoryUsageForProcess(long pid)
{
long mem = 0;
int pHandle = OpenProcess(0x0400 | 0x0010, 0, (uint)pid);
try
{
PROCESS_MEMORY_COUNTERS pmc = new PROCESS_MEMORY_COUNTERS();
if (GetProcessMemoryInfo(pHandle, pmc, 40) != 0)
mem = pmc.WorkingSetSize;
}
finally
{
CloseHandle(pHandle);
}
return mem;
}

public static string ToString(long numOfBytes)
{
double bytes = numOfBytes;
if (bytes < 1024) return bytes.ToString(); bytes /= 1024; if (bytes < 1024) { return bytes.ToString("#.# KB"); } else { bytes /= 1024; if (bytes < 1024) { return bytes.ToString("#.# MB"); } else { bytes /= 1024; return bytes.ToString("#.# GB"); } } } public static string GetFormattedMemoryUsageForProcess(long pid) { return ToString(GetMemoryUsageForProcess(pid)); } } [/code]