I have an application that uses a lot of memory, but it is a normal situation. I need to inform user if there is not enough memory to perform an operation. I know that x86 proces开发者_开发知识库s can allocate less then 2 GB user memory. But x64 process can allocate much more user memory depending on physical memory. Earlier the application supported x86 platform only and I used the following code:
private bool CheckMemoryInternal(long bytesCountToCheck) {
// Get physical memory of the current workstation
long memSize = long.MaxValue;
NativeMethods.MEMORYSTATUSEX memory = new NativeMethods.MEMORYSTATUSEX();
memory.dwLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(memory);
if (UnsafeNativeMethods.GlobalMemoryStatusEx(ref memory))
memSize = (long)memory.ullTotalPhys;
// Don't know the reason, but this value is measured in kilobytes, and MSDN wrote that it is measured in bytes
long maxWorkingSet = (long)Process.GetCurrentProcess().MaxWorkingSet * 1024;
// Obtain the maximal amount of memory for our app
// If the current amount of physical memory is less than maxWorkingSet, we can use it, but it should not be less than 512 MB for our application.
long maxMemorySize = Math.Min(Math.Max(512 * OneMegaByte, memSize), maxWorkingSet);
return bytesCountToCheck + Process.GetCurrentProcess().PrivateMemorySize64 < maxMemorySize;
}
I know one more way to do that:
private bool CheckMemoryInternal(long megaBytes) {
try {
byte[][] chunks = new byte[megaBytes][];
for (int i = 0; i < chunks.Length; i++)
chunks[i] = new byte[1024 * 1024];
return true;
}
catch (OutOfMemoryException) {
return false;
}
}
But I don't like this way.
Now I migrated the application to the x64 platform. And at first the code sample didn't work correctly. The maximal size of the allowed memory used for allocating remained the same as in the x86 application (MaxWorkingSet(32 bit) == MaxWorkingSet(64 bit)). I tried to allocate a lot of memory on a x64 machine and I succeeded. I was able to allocate 4Gb memory on a x64 machine with 4Gb physical memory, and after that I've got the OutOfMemory exception.
How can I check the possibility of allocating a certain amount of memory on the x64 platform?
That's not at all how Windows works. It is a virtual memory operating system. You get OOM when you can no longer allocate any more virtual memory. Physical memory (RAM) has nothing to do with it.
When your code runs in 32-mode, it has 2 gigabytes of addressable virtual memory. OOM happens when you try to allocate a chunk of memory and there isn't a hole left that's big enough to fit the request. Large allocations fail earlier. Never assume you can allocate everything, once a program has allocated more than a gigabyte, the odds that it will fail start to increase rapidly.
A problem that's solved on 64-bit operating system. Addressable virtual memory size is somewhere between 192 gigabytes and 2 terabytes, depends on the Windows version. The constraint is now how much of that huge address space is mappable. The maximum size of the paging file. Which is a moving target, the paging file is shared by other processes. When you get close to the limit you have much bigger problems, like garbage collections that take forever. You just don't bother anymore telling the user how close to OOM she gets, she already knows from your program not being responsive anymore.
Windows Internals is a good book to learn more about the way Windows works.
See MemoryFailPoint for a way to verify allocations without having the unpredictability of trying to intercept an OutOfMemoryException. Note that this works for x86 as well as for x64.
精彩评论