Сотрудник несколько месяцев назад упомянул мне, что одно из наших внутренних приложений Delphi, похоже, занимает 8 ГБ оперативной памяти. Я сказал ему:
Это невозможно
32-разрядное приложение имеет только 32-разрядное виртуальное адресное пространство. Даже если произошла утечка памяти, большая часть памяти, которую он может потреблять, составляет 2 ГБ. После этого выделения будут сбой (поскольку в виртуальном адресном пространстве не будет пустое пространство). И в случае утечки памяти виртуальные страницы будут заменены на файл подкачки, освобождая физическую память.
Но он отметил, что Windows Resource Monitor указал, что в системе доступно менее 1 ГБ ОЗУ. И хотя наше приложение использовало только 220 МБ виртуальной памяти: при закрытии он освободил 8 ГБ физической памяти.
Итак, я протестировал его
Я пропустил приложение на несколько недель, и сегодня я, наконец, решил проверить его.
Сначала я рассмотрю использование памяти перед закрытием приложения:
- рабочий набор (ОЗУ) 241 МБ
- общая используемая виртуальная память: 409 МБ
И я использовал Resource Monitor для проверки памяти, используемой приложением, и используемой общей оперативной памяти:
- виртуальная память, выделенная приложением: 252 МБ
- используемая физическая память: 14 ГБ
И затем использование памяти после закрытия приложения:
- используемая физическая память: 6.6 ГБ (на 7.4 ГБ ниже)
Я также использовал Process Explorer для просмотра разбивки физической памяти до и после. Единственное различие заключается в том, что 8 ГБ оперативной памяти действительно не было выполнено и теперь бесплатное:
| Item | Before | After |
|-------------------------------|------------|-----------|
| Commit Charge (K) | 15,516,388 | 7,264,420 |
| Physical Memory Available (K) | 1,959,480 | 9,990,012 |
| Zeroed Paging List (K) | 539,212 | 8,556,340 |
Примечание. Интересно, что Windows теряет время, мгновенно обнуляя всю память, вместо того, чтобы просто помещать ее в резервный список и нулевое при необходимости (так как запросы памяти должны быть удовлетворены).
Ни одна из этих вещей не объясняет, что оперативная память была делает (что вы делаете, просто сидите там! Что вы содержите!?)
Что в этой памяти!
В этой ОЗУ должно быть полезно что-то; он должен иметь некоторые цели. Для этого я обратился к SysInternals RAMMap. Он может распределять память по памяти.
Единственная подсказка, которую предоставляет RAMMap, заключается в том, что 8 ГБ физической памяти были связаны с чем-то вроде Session Private. Эти Сеансы Private не связаны с каким-либо процессом (т.е. Не мой процесс):
| Item | Before | After |
|------------------------|----------|----------|
| Session Private | 8,031 MB | 276 MB |
| Unused | 1,111 MB | 8,342 MB |
Я, конечно, ничего не делаю с EMS, XMS, AWE и т.д.
Что может произойти в 32-разрядном не-администраторском приложении, которое заставляет Windows выделять дополнительно 7 ГБ ОЗУ?
- Это не кэш обмениваемых элементов
- это не кеш SuperFetch
Это просто; потребляющей ОЗУ.
Сессия приватная
Единственная информация о "приватной сессии" - это сообщение в блоге с объявлением RAMMap:
Сессия приватная: Память, которая является частной для определенного сеанса. Это будет выше на серверах Host Host RDS.
Какое приложение это
Это 32-разрядное собственное приложение Windows (т.е. не Java, а не .NET). Поскольку он является родным приложением Windows, он, конечно же, активно использует Windows API.
Следует отметить, что я не просил людей отлаживать приложение; я надеялся, что разработчик Windows узнает, почему Windows может хранить память, которую я никогда не выделял. Сказав это, единственное, что изменилось в последнее время (за последние 2 или 3 года), которое может вызвать такую вещь, - это функция, которая снимает скриншот каждые 5 минут и сохраняет его в пользовательской папке %LocalAppData%
. Таймер срабатывает каждые пять минут:
QueueUserWorkItem(TakeScreenshotThreadProc);
И псевдокод метода потока:
void TakeScreenshotThreadProc(Pointer data)
{
String szFolder = GetFolderPath(CSIDL_LOCAL_APPDTA);
ForceDirectoryExists(szFolder);
String szFile = szFolder + "\" + FormatDateTime('yyyyMMdd"_"hhnnss', Now()) + ".jpg";
Image destImage = new Image();
try
{
CaptureDesktop(destImage);
JPEGImage jpg = new JPEGImage();
jpg.CopyFrom(destImage);
jpg.CompressionQuality = 13;
jpg.Compress();
HANDLE hFile = CreateFile(szFile, GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, null, CREATE_ALWAYS,
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_ENCRYPTED, 0);
//error checking elucidated
try
{
Stream stm = new HandleStream(hFile);
try
{
jpg.SaveToStream(stm);
}
finally
{
stm.Free();
}
}
finally
{
CloseHandle(hFile);
}
}
finally
{
destImage.Free();
}
}