Вопрос

Существует множество методов выделения памяти в среде Windows, таких как VirtualAlloc, HeapAlloc, malloc, new.

Таким образом, в чем разница между ними?

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

Решение

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

Виртуальное распределение

Низкоуровневый Windows API, предоставляющий множество опций, но в основном полезный для людей в довольно специфических ситуациях.Может выделять память только в (редактировать:не 4 КБ) большими кусками.Бывают ситуации, когда вам это нужно, но вы поймете, когда окажетесь в одной из таких ситуаций.Одна из наиболее распространенных - это когда вам приходится совместно использовать память напрямую с другим процессом.Не используйте его для выделения памяти общего назначения.Использование VirtualFree чтобы освободить место.

Куча валок

Выделяет любой объем памяти, который вы запрашиваете, не большими кусками, чем VirtualAlloc. HeapAlloc знает, когда ему нужно позвонить VirtualAlloc и делает это за вас автоматически.Нравится malloc, но доступен только для Windows и предоставляет еще пару опций.Подходит для выделения общих фрагментов памяти.Некоторые API-интерфейсы Windows могут потребовать, чтобы вы использовали это для выделения памяти, которую вы им передаете, или использовали его дополнение HeapFree чтобы освободить память, которую они вернут вам.

маллок

Способ выделения памяти на языке Си.Предпочитайте это, если вы пишете на C, а не на C ++, и вы хотите, чтобы ваш код работал, напримерКомпьютеры Unix тоже, или кто-то специально говорит, что вам нужно его использовать.Не инициализирует память.Подходит для выделения общих фрагментов памяти, таких как HeapAlloc.Простой API.Использование free чтобы освободить место.Visual C++'s malloc звонки HeapAlloc.

новое

Способ выделения памяти на C ++.Предпочитайте это, если вы пишете на C ++.Он также помещает объект или объекты в выделенную память.Использование delete чтобы освободить (или delete[] для массивов).Visual studio - это new звонки HeapAlloc, а затем, возможно, инициализирует объекты, в зависимости от того, как вы это вызываете.

В последних стандартах C ++ (C ++ 11 и выше), если вам приходится вручную использовать delete, вы делаете это неправильно и должны использовать умный указатель Нравится unique_ptr вместо этого.Начиная с C ++ 14, то же самое можно сказать и о new (заменен такими функциями , как make_unique()).


Есть также пара других подобных функций, таких как SysAllocString которые вам, возможно, скажут, что вы должны использовать в определенных обстоятельствах.

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

VirtualAlloc представляет собой специализированное выделение виртуальной памяти операционной системы (VM).Распределения в системе виртуальной машины должны выполняться с детализацией распределения, которая (степень детализации распределения) зависит от архитектуры.Выделение в системе виртуальной машины - это одна из самых основных форм выделения памяти.Выделение виртуальных машин может принимать несколько форм, память не обязательно выделяется или физически резервируется в ОЗУ (хотя это может быть).Выделение виртуальной машины обычно представляет собой особая цель тип распределения, либо из-за того, что распределение должно

  • быть очень большим,
  • нуждается в совместном использовании,
  • должны быть выровнены по определенному значению (соображения производительности) или
  • вызывающему не обязательно использовать всю эту память сразу...
  • и т.д...

HeapAlloc по сути, это то, что malloc и new оба в конце концов звонят.Он разработан таким образом, чтобы быть очень быстрым и пригодным для использования во многих различных типах сценариев распределения общего назначения.Это "Куча" в классическом смысле.Кучи на самом деле настраиваются с помощью VirtualAlloc, который является тем , что используется для изначально зарезервируйте выделенное пространство из операционной системы.После инициализации пробела с помощью VirtualAlloc, различные таблицы, списки и другие структуры данных сконфигурированы для поддержания работы кучи и управления ею.Некоторые из этих операций выполняются в форме динамического изменения размера (увеличения и сжатия) кучи, адаптации кучи к конкретным условиям использования (частые выделения определенного размера) и т.д..

new и malloc являются в чем - то одинаковыми, malloc по сути, это точный вызов в HeapAlloc( heap-id-default ); new однако можно [дополнительно] настроить выделяемую память для C ++ Объекты.Для данного объекта C ++ сохранит vtables в куче для каждого вызывающего.Эти vtables являются перенаправлениями для выполнения и являются частью того, что придает C ++ его OO-характеристикам, таким как наследование, перегрузка функций и т.д...

Некоторые другие распространенные методы распределения, такие как _alloca() и _malloca() являются стек основанный;FileMappings действительно распределяются с VirtualAlloc и устанавливается с определенными битовыми флагами, которые определяют, что эти сопоставления должны иметь тип FILE.

Большую часть времени вы должны выделять память таким образом, который согласуется с использованием этой памяти ;). new в C++, malloc для C, VirtualAlloc для массивных случаев или IPC.

*** Обратите внимание, что большие выделения памяти, выполняемые HeapAlloc фактически отправлены в VirtualAlloc после некоторого размера (пара сотен кб или 16 МБ или что-то еще, что я забыл, но довольно большое :)).

*** РЕДАКТИРОВАТЬ Я кратко упомянул об IPC и VirtualAlloc, есть также что - то очень аккуратное в связанном VirtualAlloc который никто из ответивших на этот вопрос не обсуждал.

VirtualAllocБывший это то, что один процесс может использовать для выделения памяти в адресном пространстве другой процесс.Наиболее типично это используется в сочетании чтобы получить удаленное выполнение в контексте другого процесса через Создатьэмоциональный поток (аналогично CreateThread, поток просто запускается в другом процессе).

Очень важно понимать различие между API-интерфейсами выделения памяти (в Windows), если вы планируете использовать язык, требующий управления памятью (например, C или C ++.). И лучший способ проиллюстрировать это, ИМХО, с помощью диаграммы:

enter image description here

Обратите внимание, что это очень упрощенный вид, специфичный для Windows.

Способ понять эту диаграмму заключается в том, что чем выше на диаграмме находится метод выделения памяти, тем более высокий уровень реализация, которую он использует.Но давайте начнем с самого низа.

Диспетчер памяти в режиме ядра

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

Виртуальное распределение / Виртуально свободный

Это те самые самый низкий уровень API, доступные из пользовательский режимVirtualAlloc функция в основном вызывает Выделять виртуальную память это, в свою очередь, быстро системный вызов Для ring0 чтобы передать дальнейшую обработку диспетчеру памяти ядра.Это также самый быстрый способ зарезервировать / выделить блок новой памяти из всех доступных в пользовательском режиме.

Но это связано с двумя основными условиями:

  • Он выделяет только блоки памяти, выровненные по границе детализации системы.

  • Он выделяет только блоки памяти размера, кратного степени детализации системы.

Так что же это такое детализация системы?Вы можете получить его, позвонив GetSystemInfo Получает системную информацию.Он возвращается как dwAllocationGranularity параметр.Его значение зависит от реализации (и, возможно, аппаратного обеспечения), но во многих 64-разрядных системах Windows оно установлено на 0x10000 байты, или 64K.

Итак, что все это означает, так это то, что если вы попытаетесь выделить, скажем, всего лишь 8-байтовый блок памяти с VirtualAlloc:

void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

В случае успеха, pAddress будут выровнены по 0x10000 граница байта.И даже при том, что вы запросили всего 8 байт, фактический блок памяти, который вы получите, будет составлять весь page (или, что-то вроде 4K байты.Точный размер страницы возвращается в dwPageSize параметр.) Но, вдобавок ко всему, весь блок памяти, охватывающий 0x10000 байты (или 64K в большинстве случаев) из pAddress не будет быть доступным для любых дальнейших распределений.Таким образом, в некотором смысле, выделяя 8 байт, вы с таким же успехом могли бы запрашивать 65536.

Итак, мораль этой истории заключается в том, чтобы не подменять VirtualAlloc для общего выделения памяти в вашем приложении.Он должен использоваться для очень специфических случаев, как это делается с куча ниже.(Обычно для резервирования / выделения больших блоков памяти.)

Используя VirtualAlloc неправильная настройка может привести к серьезной фрагментации памяти.

Создать кучу / Куча валок / Без кучи / Куча разрушений

В двух словах, куча функции - это, по сути, оболочка для VirtualAlloc функция.Другие ответы здесь дают довольно хорошее представление об этом.Я добавлю, что, с очень упрощенной точки зрения, способ куча работает ли это:

  • HeapCreate резервирует большой блок виртуальной памяти, вызывая VirtualAlloc внутренне (или ZwAllocateVirtualMemory чтобы быть конкретным).Он также настраивает внутреннюю структуру данных, которая может отслеживать дальнейшее распределение меньшего размера в пределах зарезервированного блока виртуальной памяти.

  • Какие-либо звонки в HeapAlloc и HeapFree фактически не выделяйте / освобождайте какую-либо новую память (если, конечно, запрос не превышает то, что уже было зарезервировано в HeapCreate) но вместо этого они метр вне (или commit) ранее зарезервированный большой фрагмент, разбивая его на более мелкие блоки памяти, которые запрашивает пользователь.

  • HeapDestroy в свою очередь призывает VirtualFree это фактически освобождает виртуальную память.

Таким образом, все это делает куча функции - идеальные кандидаты для общего выделения памяти в вашем приложении.Это отлично подходит для выделения памяти произвольного размера.Но небольшая цена, которую приходится заплатить за удобство куча функций заключается в том, что они вносят небольшие накладные расходы по VirtualAlloc при резервировании больших блоков памяти.

Еще одна хорошая вещь о куча заключается в том, что на самом деле вам не нужно его создавать.Обычно он создается для вас при запуске вашего процесса.Таким образом, к нему можно получить доступ, позвонив Получить processsheap функция.

маллок / бесплатно

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

Это рекомендуемый способ выделения / освобождения памяти, если вы программируете на C.(Если только вы не кодируете конкретный драйвер устройства в режиме ядра.)

новое / удалить

Приходите как высокий уровень (ну, для C++) операторы управления памятью.Они специфичны для C++ язык, и как malloc для C, также являются оболочками для heap функции.У них также есть целая куча собственного кода, который имеет дело C++-специфическая инициализация конструкторов, освобождение в деструкторах, создание исключения и т.д.

Эти функции являются рекомендуемым способом выделения / освобождения памяти и объектов, если вы программируете в C++.


Наконец, один комментарий, который я хочу сделать по поводу того, что было сказано в других ответах об использовании VirtualAlloc для совместного использования памяти между процессами. VirtualAlloc сам по себе не позволяет совместно использовать свою зарезервированную / выделенную память с другими процессами.Для этого нужно использовать CreateFileMapping API, который может создать именованный блок виртуальной памяти, который может быть совместно использован с другими процессами.Он также может сопоставить файл на диске с виртуальной памятью для доступа на чтение / запись.Но это уже другая тема.

В общих чертах:

  • VirtualAlloc, HeapAlloc и т.д.это API-интерфейсы Windows, которые выделяют память различных типов непосредственно из операционной системы.VirtualAlloc управляет страницами в системе виртуальной памяти Windows, в то время как HeapAlloc выделяет из определенной кучи операционной системы.Честно говоря, вам вряд ли когда-нибудь понадобится использовать любой из них.

  • malloc - это стандартная библиотечная функция C (и C ++), которая выделяет память вашему процессу.Реализации malloc обычно используют один из API ОС для создания пула памяти при запуске вашего приложения, а затем выделяют его при выполнении запросов malloc

  • new - это стандартный оператор C ++, который выделяет память, а затем соответствующим образом вызывает конструкторы в этой памяти.Это может быть реализовано в терминах malloc или в терминах API операционной системы, и в этом случае он также обычно создает пул памяти при запуске приложения.

VirtualAlloc ===> sbrk() под UNIX

HeapAlloc ====> malloc() под UNIX

VirtualAlloc => Выделяется непосредственно в виртуальную память, вы резервируете / фиксируете ее блоками.Это отлично подходит для больших распределений, например больших массивов.

HeapAlloc / new => выделяет память в куче по умолчанию (или любой другой куче, которую вы можете создать).Это распределяется по каждому объекту и отлично подходит для небольших объектов.Куча по умолчанию сериализуема, поэтому она имеет гарантированное распределение потоков (это может вызвать некоторые проблемы в сценариях высокой производительности, и именно поэтому вы можете создавать свои собственные кучи).

malloc => использует кучу времени выполнения C, аналогичную HeapAlloc но это обычное явление для сценариев совместимости.

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

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

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