Всем доброго времени суток, хотелось бы прояснить ситуацию с потоком разыменования сегментов в винде, насколько я понимаю дела обстоят так: В ядре есть глобальная переменная MmUnusedSegmentList, которая представляет собой список объектов CONTROL_AREA (или LARGE_CONTROL_AREA в случае per-session контрольной области), объект SEGMENT которых предназначен для удаления. Объекты CONTROL_AREA попадают в этот список в общем случае когда: if ((ControlArea->NumberOfMappedViews == 0) && (ControlArea->NumberOfSectionReferences == 0) && (ControlArea->u.Flags.BeingDeleted == 0)) { Такие проверки производятся при каждом декрементировании переменной NumberOfMappedViews и NumberOfSectionReferences, этим занимается функция MiCheckControlArea (заносит контрольные области в этот список). Уничтожение самих сегментов производит функция MiRemoveUnusedSegments, которая вызывается только в одном месте, из функции MiDereferenceSegmentThread. MiDereferenceSegmentThread – этот системный поток, который занимается удалением неиспользуемых в данный момент сегментов из памяти (и ещё расширением страничных файлов), освобождая тем самым место в страничном файле. Делает он это по требованию ОС. ОС выставляет событие MmUnusedSegmentCleanup, поток ждёт этого события и получив его, удаляет ненужные сегменты, освобождая место в страничном файле. Возникает вопрос, зачем для всего этого нужен отдельный поток ? Почему нельзя удалять сегменты, на которые нет ссылок в момент проверки, т.е прямо в функции MiCheckControlArea ?
Наткнулся ещё вот на что: Код (Text): if (ControlArea->NumberOfPfnReferences == 0) { // // There are no views and no physical pages referenced // by the Segment, dereference the Segment object. // и Код (Text): ULONG NumberOfPfnReferences; // valid + transition prototype PTEs Этот код из MiCheckControlArea и если NumberOfPfnReferences == 0, то сама MiCheckControlArea удалит сегмент и не будет заносит его в список MmUnusedSegmentList !, для последующего удаления из MiDereferenceSegmentThread. Т.е, получается что если у сегмента есть валидные или transition PTE, то удалять сразу его нельзя, а если все его PTE невалидные и не transition, то можно. Но почему ? Ссылок же на сегмент всё-равно нет, можно ж просто слить все изменённые PTE в файл (если сегмент поддерживается не страничным файлом) и удалить его...
Поразмыслив, появилось мнение почему так сделано (хотя и не очень убедительное): Допустим у нас поток имеют доступ к сегменту через секцию (или субсекцию, пока в этом ещё не разобрался через что именно производится работа с сегментом), т.е спроецировал он секцию, NumberOfMappedViews стало = 1, потом проекцию удалил, т.е NumberOfMappedViews = 0 и, скорее всего, NumberOfPfnReferences != 0, т.к он совсем недавно работал с секцией и наверняка какие-то страницы ещё лежат в физической памяти. Теперь допустим он мапит секцию заново и в этом случае всё очень просто, сегмент ещё лежит в памяти, нужно просто дать на него ссылку, не нужно выделять новый сегмент, плюс к этому даже страницы остались в физ. памяти, можно сново к ним обратиться и это не займёт много времени. А если бы сегмент удалялся сразу, то при каждом повторном мапиньи секции пришлось бы создавать сегмент и т.д. Но опять таки, как часто программы открывают и закрывают один и тот же файл для проецирования, это же глупо. Неужели только ради того чтобы оптимизировать подобную ситуацию разработчики винды придумали этот MiDereferenceSegmentThread и т.д.