#c# #.net #64-bit #out-of-memory
#c# #.net #64-разрядный #нехватка памяти
Вопрос:
У меня есть приложение, которое использует много памяти, но это нормальная ситуация. Мне нужно сообщить пользователю, недостаточно ли памяти для выполнения операции. Я знаю, что процесс x86 может выделять пользовательскую память объемом менее 2 ГБ. Но процесс x64 может выделять гораздо больше памяти пользователя в зависимости от физической памяти. Ранее приложение поддерживало только платформу x86, и я использовал следующий код:
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;
}
Я знаю еще один способ сделать это:
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;
}
}
Но мне не нравится этот способ.
Теперь я перенес приложение на платформу x64. И сначала пример кода работал некорректно. Максимальный размер разрешенной памяти, используемой для выделения, остался таким же, как и в приложении x86 (MaxWorkingSet(32 бит) == MaxWorkingSet(64 бит)). Я попытался выделить много памяти на машине x64, и мне это удалось. Я смог выделить 4 ГБ памяти на компьютере x64 с 4 ГБ физической памяти, и после этого я получил исключение OutOfMemory.
Как я могу проверить возможность выделения определенного объема памяти на платформе x64?
Комментарии:
1. Вам необходимо убедиться, что ваша программа действительно выполняется как 64-битный процесс. 32-битные процессы в 64-битной ОС могут фактически иметь 4 ГБ пользовательского пространства. Убедитесь, что «целевая платформа» вашего проекта — x64.
2. Похоже, ваше приложение представляет собой 32-разрядный процесс. Вам необходимо убедиться, что приложение является 64-разрядным процессом, прежде чем выделять более 4 ГБ памяти.
3. Я уверен, что приложение работает в 64-битном режиме. Мне нужно предотвратить исключение OutOfMemoryException перед выделением памяти.
Ответ №1:
Это совсем не так, как работает Windows. Это операционная система с виртуальной памятью. Вы получаете ООМ, когда вы больше не можете выделять больше виртуальной памяти. Физическая память (ОЗУ) не имеет к этому никакого отношения.
Когда ваш код выполняется в 32-режиме, он имеет 2 гигабайта адресуемой виртуальной памяти. ООМ происходит, когда вы пытаетесь выделить фрагмент памяти, и не остается дыры, достаточно большой, чтобы вместить запрос. Большие выделения завершаются неудачей раньше. Никогда не предполагайте, что вы можете выделить все, как только программа выделила более гигабайта, вероятность того, что она завершится неудачей, начинает быстро увеличиваться.
Проблема, которая решается в 64-разрядной операционной системе. Размер адресуемой виртуальной памяти составляет где-то от 192 гигабайт до 2 терабайт, зависит от версии Windows. Теперь ограничение заключается в том, какая часть этого огромного адресного пространства может быть отображена. Максимальный размер файла подкачки. Который является движущейся целью, файл подкачки совместно используется другими процессами. Когда вы приближаетесь к пределу, у вас возникают гораздо большие проблемы, такие как сборка мусора, которая длится вечно. Вы просто больше не беспокоитесь о том, чтобы сообщить пользователю, насколько близко он подходит к ООМ, он уже знает, что ваша программа больше не реагирует.
Windows Internals — хорошая книга, чтобы узнать больше о том, как работает Windows.
Комментарии:
1. То есть вы имеете в виду, что я не могу найти объем памяти, который я могу выделить 64-разрядному процессу до момента, когда произойдет исключение OutOfMemoryException? Спасибо за ваше объяснение и рекомендации по поводу книги.
Ответ №2:
Способ проверки выделения без непредсказуемости попытки перехватить исключение OutOfMemoryException см. в разделе MemoryFailPoint. Обратите внимание, что это работает как для x86, так и для x64.
Комментарии:
1. Я уже пробовал, и он всегда возвращает количество памяти меньше, чем фактическое доступное количество.