Критические разделы, из-за которых происходит утечка памяти в Vista / Win2008?

StackOverflow https://stackoverflow.com/questions/804848

Вопрос

Похоже, что частое использование критических разделов в Vista / Windows Server 2008 приводит к тому, что ОС не полностью восстанавливает память.Мы обнаружили эту проблему в приложении Delphi, и это явно связано с использованием CS API.(смотрите это ИТАК, вопрос)

Кто-нибудь еще видел это в приложениях, разработанных на других языках (C ++, ...)?

Пример кода просто инициализировал 10000000 CS, а затем удалил их.Это отлично работает в XP / Win2003, но не освобождает всю максимальную память в Vista / Win2008 до завершения работы приложения.
Чем больше вы используете CS, тем больше ваше приложение тратит память впустую.

Это было полезно?

Решение

Microsoft действительно изменила этот способ InitializeCriticalSection работает в Vista, Windows Server 2008 и, вероятно, также в Windows 7.
Они добавили "функцию" для сохранения некоторой памяти, используемой для отладочной информации, когда вы выделяете кучу CS.Чем больше вы выделяете, тем больше памяти сохраняется.Это может быть асимптотично и в конечном итоге выровняться (не полностью соответствует этому).
Чтобы избежать этой "функции", вы должны использовать новый API Инициализировать критический разделex и передайте флаг CRITICAL_SECTION_NO_DEBUG_INFO.
Преимущество этого заключается в том, что это может быть быстрее, так как очень часто используется только spincount без необходимости фактического ожидания.
Недостатки заключаются в том, что ваши старые приложения могут быть несовместимы, вам нужно изменить свой код, и теперь он зависит от платформы (вы должны проверить версию, чтобы определить, какую из них использовать).А также вы теряете возможность отладки, если вам нужно.

Тестовый набор для замораживания Windows Server 2008:
- создайте этот пример C ++ следующим образом CSTest.exe

#include "stdafx.h" 
#include "windows.h" 
#include <iostream> 

using namespace std; 

void TestCriticalSections() 
{ 
  const unsigned int CS_MAX = 5000000; 
  CRITICAL_SECTION* csArray = new CRITICAL_SECTION[CS_MAX];  

  for (unsigned int i = 0; i < CS_MAX; ++i)  
    InitializeCriticalSection(&csArray[i]);  

  for (unsigned int i = 0; i < CS_MAX; ++i)  
    EnterCriticalSection(&csArray[i]);  

  for (unsigned int i = 0; i < CS_MAX; ++i)  
    LeaveCriticalSection(&csArray[i]);  

  for (unsigned int i = 0; i < CS_MAX; ++i)  
    DeleteCriticalSection(&csArray[i]); 

  delete [] csArray; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
  TestCriticalSections(); 

  cout << "just hanging around..."; 
  cin.get(); 

  return 0; 
}

-...Запустите этот пакетный файл (требуется пакет SDK от сервера sleep.exe)

@rem you may adapt the sleep delay depending on speed and # of CPUs 
@rem sleep 2 on a duo-core 4GB. sleep 1 on a 4CPU 8GB. 

@for /L %%i in (1,1,300) do @echo %%i & @start /min CSTest.exe & @sleep 1 
@echo still alive? 
@pause 
@taskkill /im cstest.* /f

-... и увидите, что сервер Win2008 с 8 ГБ и четырехъядерным процессором зависает, не достигнув 300 запущенных экземпляров.
-... повторите на сервере Windows 2003 и увидите, что он справится с этим как по волшебству.

Другие советы

Ваш тест, скорее всего, не отражает проблему.Критические секции считаются "облегченными мьютексами", потому что реальный мьютекс ядра не создается при инициализации критической секции.Это означает, что ваши 10-миллиметровые критические разделы представляют собой всего лишь структуры с несколькими простыми элементами.Однако, когда два потока обращаются к CS одновременно, для их синхронизации действительно создается мьютекс - и это совсем другая история.

Я предполагаю, что в вашем реальном приложении потоки действительно сталкиваются, в отличие от вашего тестового приложения.Теперь, если вы действительно рассматриваете критические разделы как облегченные мьютексы и создаете их много, ваше приложение может выделять большое количество реальных мьютексов ядра, которые намного тяжелее, чем объект light critical section.А поскольку мьютексы являются объектами ядра, их создание в чрезмерном количестве может действительно навредить операционной системе.

Если это действительно так, вам следует сократить использование критических разделов, где вы ожидаете много столкновений.Это не имеет никакого отношения к версии Windows, так что мое предположение может быть ошибочным, но все равно стоит кое-что рассмотреть.Попробуйте отследить количество дескрипторов операционной системы и посмотреть, как работает ваше приложение.

Ты видишь что-то еще.

Я только что собрал и запустил этот тестовый код.Каждая статистика использования памяти постоянна - личные байты, рабочий набор, фиксация и так далее.

int _tmain(int argc, _TCHAR* argv[])
{
    while (true)
    {
        CRITICAL_SECTION* cs = new CRITICAL_SECTION[1000000];
        for (int i = 0; i < 1000000; i++) InitializeCriticalSection(&cs[i]);
        for (int i = 0; i < 1000000; i++) DeleteCriticalSection(&cs[i]);
        delete [] cs;
    }

    return 0;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top