Я пытаюсь проследить огромное замедление функций памяти кучи в Windows Vista и Windows 7 (я не тестировал на каких-либо серверных версиях). Это вообще не происходит в Windows XP, только в новых операционных системах Microsoft.
Я изначально столкнулся с этой проблемой, когда PHP выполнялся в Windows. Похоже, что сами скрипты выполнялись с ожидаемой скоростью, но после выполнения script я столкнулся с 1-2 секундами задержки во внутренних функциях выключения PHP. После запуска отладки я увидел, что это связано с использованием диспетчера памяти PHP HeapAlloc
/HeapFree
/HeapReAlloc
.
Я проследил его до использования флага HEAP_NO_SERIALIZE
для функций кучи:
#ifdef ZEND_WIN32
#define ZEND_DO_MALLOC(size) (AG(memory_heap) ? HeapAlloc(AG(memory_heap), HEAP_NO_SERIALIZE, size) : malloc(size))
#define ZEND_DO_FREE(ptr) (AG(memory_heap) ? HeapFree(AG(memory_heap), HEAP_NO_SERIALIZE, ptr) : free(ptr))
#define ZEND_DO_REALLOC(ptr, size) (AG(memory_heap) ? HeapReAlloc(AG(memory_heap), HEAP_NO_SERIALIZE, ptr, size) : realloc(ptr, size))
#else
#define ZEND_DO_MALLOC(size) malloc(size)
#define ZEND_DO_FREE(ptr) free(ptr)
#define ZEND_DO_REALLOC(ptr, size) realloc(ptr, size)
#endif
и (который фактически устанавливает значение по умолчанию для HeapAlloc
/HeapFree
/HeapReAlloc
) в функции start_memory_manager
:
#ifdef ZEND_WIN32
AG(memory_heap) = HeapCreate(HEAP_NO_SERIALIZE, 256*1024, 0);
#endif
Я удалил параметр HEAP_NO_SERIALIZE
(заменил на 0) и устранил проблему. Скрипты теперь быстро очищаются как в CLI, так и в версии SAPI Apache 2. Это было для PHP 4.4.9, но исходный код PHP 5 и 6 (в разработке) содержит тот же флаг в вызовах.
Я не уверен, что то, что я сделал, было опасно или нет. Все это часть менеджера памяти PHP, поэтому мне придется делать некоторые копания и исследования, но это вызывает вопрос:
Почему функция памяти кучи настолько медленная в Windows Vista и Windows 7 с HEAP_NO_SERIALIZE
?
Во время исследования этой проблемы я придумал ровно один хороший удар. Пожалуйста, прочитайте сообщение в блоге http://www.brainfarter.net/?p=69, где плакат объясняет эту проблему и предлагает тестовый пример (как исходный, так и двоичный файл), чтобы выделить проблему.
Мои тесты на четырехъядерном 8-ядерном 8-ядерном 8-ядерном компьютере Windows 7 дают 43 836. Ой! Те же результаты без флага HEAP_NO_SERIALIZE
655, ~ 70x быстрее в моем случае.
Наконец, кажется, что любая программа, созданная с использованием Visual С++ 6 с использованием malloc
/free
или new
/delete
, кажется, затронута на этих новых платформах. Компилятор Visual С++ 2008 не устанавливает этот флаг по умолчанию для этих функций/операторов, поэтому они не затрагиваются - но это все еще оставляет много затронутых программ!
Я рекомендую вам загрузить доказательство концепции и попробовать. Эта проблема объясняет, почему мой обычный PHP на установке Windows обход и может объяснить, почему Windows Vista и Windows 7 кажутся медленнее время от времени.
UPDATE 2010-01-26: Я получил ответ от Microsoft, в котором говорится, что кучка с низкой фрагментацией (LFH) является фактической политикой дефолта для куч, которые содержат сколько-нибудь заметное количество распределений. В Windows Vista они реорганизовали много кода для удаления дополнительных структур данных и путей кода, которые больше не являются частью общего случая для обработки вызовов API кучи. С флагом HEAP_NO_SERIALIZE
и в некоторых ситуациях отладки они не позволяют использовать LFH, и мы застряли на медленном и менее оптимизированном пути через диспетчер кучи. Поэтому... настоятельно рекомендуется не использовать HEAP_NO_SERIALIZE
, так как вы пропустите всю работу с LFH и любую будущую работу в API кучи Windows.