Может ли Win32 «перемещать» выделенную кучу память? - PullRequest
7 голосов
/ 19 января 2010

У меня есть приложение .NET / native C ++.В настоящее время код C ++ выделяет память в куче по умолчанию, которая сохраняется в течение всей жизни приложения.В основном, функции / команды выполняются в C ++, что приводит к выделению / модификации текущей постоянной памяти.Я исследую подход для отмены одной из этих функций / команд во время исполнения.У нас есть сотни этих команд, и многие из них являются очень сложным (унаследованным) кодом.

Подход, который я стараюсь избегать, заключается в изменении каждой команды / функции для проверки отмены и выполнения всех действий.соответствующая очистка (освобождение памяти кучи).Я исследую многопоточный подход, в котором дополнительный поток получает запрос отмены и завершает поток выполнения команды.Я хотел бы, чтобы вся динамическая память была выделена в «приватной куче», используя HeapCreate() (Win32).Таким образом, приватная куча может быть уничтожена потоком, обрабатывающим запрос отмены.Однако, если команда выполняется до конца, мне нужно, чтобы динамическая память сохранялась.В этом случае я хотел бы сделать логический эквивалент «перемещения» памяти частной кучи в кучу по умолчанию / к процессу без затрат на фактическую копию.Это каким-либо образом возможно?Имеет ли это хоть какой-то смысл?

В качестве альтернативы, я признаю, что я мог бы просто иметь новую приватную кучу для каждого выполнения команды / функции (каждый будет новым потоком).Закрытая куча может быть уничтожена, если команда отменена, или выживет, если команда завершится.Есть ли проблема с числом куч, растущих бесконечно?Я знаю, что с каждой кучей связаны некоторые накладные расходы.С какими ограничениями я могу столкнуться?

Я использую 64-разрядную версию Windows 7 с 8 ГБ ОЗУ (считайте это целевой платформой).Приложение, с которым я работаю, составляет около 1 миллиона SLOC (половина C ++, половина C #).Я ищу любой опыт / предложения по управлению частной кучей или просто альтернативы моему решению.

Ответы [ 4 ]

4 голосов
/ 20 января 2010

Возможно, вам лучше использовать отдельные процессы вместо отдельных потоков:

  • использовать файлы, отображенные в памяти (т.е. вообще не файл - просто кросс-обработанная общая память)
  • убийство процесса "чище", чем убийство потока
  • Я думаю, вы можете иметь общую память "пережить" убийство без перемещения - вы отображаете / удаляете вместо перемещения

хотя вам, возможно, придется самостоятельно управлять памятью.

Во всяком случае, стоит посмотреть. Я изучал использование межпроцессной памяти для некоторых других вещей, и у нее были некоторые необычные свойства (можно вспомнить все это ясно, это было некоторое время назад), и вы могли бы воспользоваться этим.

Просто идея!

2 голосов
/ 20 января 2010

Из MSDN Функции кучи Страница: «Память, выделенная HeapAlloc, не является подвижной. Адрес, возвращаемый HeapAlloc, действителен, пока блок памяти не будет освобожден или перераспределен; блок памяти не нужно блокировать.»

Можете ли вы повторно связать унаследованные приложения с вашей собственной реализацией malloc ()? Если это так, вы должны быть в состоянии управлять без изменения остальной части кода. Ваша пользовательская библиотека malloc может отслеживать выделенные блоки по потокам и иметь функцию «FreeAllByThreadId (), которую вы вызываете после уничтожения потока устаревшей функции. Вы можете использовать частные кучи внутри библиотеки.

Альтернативой частным кучам может быть выделение файлов из отображенных в память файлов. Смотрите " Создание именованной общей памяти ." Вы создаете общую память при инициализации библиотеки alloc для устаревшего потока. В случае успеха отобразите его в основной поток, чтобы ваш c # мог получить к нему доступ; по завершении закройте его, и он будет отправлен в систему.

1 голос
/ 20 января 2010

Куча - это своего рода большой кусок памяти. Это менеджер памяти уровня пользователя. Куча создается низкоуровневыми вызовами системной памяти (например, sbrk в Linux и VirtualAlloc в Windows). В куче, затем вы можете запросить или вернуть небольшой кусок памяти с помощью malloc / new / free / delete. По умолчанию процесс имеет одну кучу (в отличие от стека, все потоки разделяют кучу). Но вы можете иметь много куч.

  • Можно ли объединить две кучи без копирования? Куча - это, по сути, структура данных, которая поддерживает список использованных и освобожденных фрагментов памяти. Таким образом, куча должна иметь своего рода бухгалтерские данные, называемые метаданными. Конечно, это метаданные за кучу. AFAIK, никакой менеджер кучи не поддерживает операцию слияния двух куч. Я рассмотрел весь исходный код реализации malloc в glibc Linux ( реализация Дуга Ли ), но такой операции не было. Функции Windows Heap * также реализованы аналогичным образом. Таким образом, в настоящее время невозможно перемещать или объединять две отдельные кучи.

  • Можно ли иметь много куч? Не думаю, что иметь много куч может быть большой проблемой. Как я уже говорил, куча - это просто структура данных, которая хранит использованные / освобожденные фрагменты памяти. Таким образом, должно быть некоторое количество накладных расходов. Но это не так серьезно. Если вы посмотрите на одну из реализаций malloc , вы увидите malloc_state, которая является базовой структурой данных для каждой кучи. Например, вы можете создать еще одну кучу с помощью create_mspace (в Windows это HeapCreate), тогда вы получите новое состояние malloc. Это не так уж и много. Так что, если этот шаг (некоторые накладные расходы на кучу и простота реализации) подойдет, тогда вы можете продолжить.

На вашем месте я постараюсь, как вы опишите. Это имеет смысл для меня. Наличие большого количества объектов кучи не приведет к большим накладным расходам.

Также следует отметить, что технически перемещение областей памяти невозможно. Указатели, которые указывали на перемещенную область памяти, будут приводить к зависанию указателей.

p.s. Ваша проблема выглядит как транзакция, особенно программная транзакционная память. Типичная реализация буферов STM, ожидающих записи в память, а затем фиксирующих в реальной системной памяти, если транзакция не имела конфликта.

1 голос
/ 19 января 2010

Нет. Память не может быть перемещена между кучами.

...