VirtualAlloc과 HeapAlloc의 차이점은 무엇입니까?


82

같은 Windows 환경에서 메모리를 할당하는 방법은 많이있다 VirtualAlloc, HeapAlloc, malloc, new.

따라서 그들 사이의 차이점은 무엇입니까?

답변:


83

각 API는 서로 다른 용도로 사용됩니다. 또한 각각은 메모리를 다 사용할 때 올바른 할당 해제 / 해제 기능을 사용해야합니다.

VirtualAlloc

많은 옵션을 제공하지만 주로 특정 상황에있는 사람들에게 유용한 저수준 Windows API입니다. 더 큰 청크 (편집 : 4KB 아님)에만 메모리를 할당 할 수 있습니다. 필요한 상황이 있지만 이러한 상황 중 하나에 해당하는 경우 알 수 있습니다. 가장 일반적인 방법 중 하나는 다른 프로세스와 직접 메모리를 공유해야하는 경우입니다. 범용 메모리 할당에는 사용하지 마십시오. VirtualFree할당을 해제하는 데 사용 합니다.

HeapAlloc

원하는 크기의 메모리를 할당합니다 VirtualAlloc.. HeapAlloc전화 VirtualAlloc가 필요한시기를 알고 자동으로 수행합니다. 과 유사 malloc하지만 Windows 전용이며 몇 가지 추가 옵션을 제공합니다. 일반적인 메모리 청크 할당에 적합합니다. 일부 Windows API에서는이를 사용하여 전달한 메모리를 할당하거나 해당 동반자 HeapFree를 사용하여 반환되는 메모리를 해제해야 할 수 있습니다.

Malloc

메모리를 할당하는 C 방식. C ++가 아닌 C로 작성하고 코드가 예를 들어 Unix 컴퓨터에서도 작동하기를 원하거나 누군가가 특별히 사용해야한다고 말하는 경우이 방법을 선호하십시오. 메모리를 초기화하지 않습니다. 같은 일반적인 메모리 청크 할당에 적합합니다 HeapAlloc. 간단한 API. free할당을 해제하는 데 사용 합니다. Visual C ++의 malloc호출 HeapAlloc.

새로운

메모리를 할당하는 C ++ 방식. C ++로 작성하는 경우 선호합니다. 객체를 할당 된 메모리에도 넣습니다. 사용 delete할당을 해제 (또는 delete[]배열). Visual Studio에서를 new호출 HeapAlloc한 다음 호출 방법에 따라 개체를 초기화 할 수 있습니다.

수동으로 사용해야하는 경우 최근 C ++ 표준 (C ++ 11 이상)에서는 delete, 당신은 잘못하고 있어요하고 사용해야하는 스마트 포인터 처럼 unique_ptr대신. C ++ 14부터는 똑같이 말할 수 있습니다 new(와 같은 함수로 대체 됨 make_unique()).


SysAllocString특정 상황에서 사용해야하는 것과 같은 몇 가지 다른 유사한 기능도 있습니다.


18
Doug : VirtualAlloc은 4kb 할당으로 엄격하게 제한되지 않으며 GetSystemInfo (), SYSTEM_INFO :: dwAllocationGranularity에서 반환하는 크기입니다. 실제로는 거의 4kb입니다. 내 호스트에서는 64k이고, 당신도 마찬가지라고 생각합니다. 4KB는 x86 ABI의 다양한 discriptor 테이블에 대한 최소 페이지 크기 항목입니다. 4KB는 R / W / X와 같이 독립적으로 허용 될 수있는 가장 작은 크기이지만 VirtualAlloc에는 중요하지 않습니다. VirtualAlloc 설명서를 참조하는 경우 LARGE_PAGES 옵션도 있습니다 ( msdn.microsoft.com/en-us/library/aa366568(VS.85).aspx 참조 ).
RandomNickName42

DirectShow가 malloc을 사용하는 대신 VirtualAlloc을 사용하여 미디어에 메모리 버퍼를 할당하는 이유를 알고 있습니까?
Aviad Rozenhek

Aviad : DirectShow는 가상 할당을 사용하여 메모리를 예약하므로 페이징 불가능과 같은 성능 최적화에 필요한 플래그를 전달하거나 하드웨어가이를 지원할 수있는 경우 성능을 향상시킬 수있는 물리적 페이지를 예약 할 수 있습니다.
RandomNickName42

8
@ RandomNickName42 : 이것은 옳지 않습니다. 할당 시작 주소는 항상 단위 (64KB)로 정렬되지만 할당 길이는 페이지 크기 (4KB)로 반올림됩니다. 실제로 주소 공간은 64KB 청크로 예약되지만 4KB 청크로 커밋됩니다. 시작 주소의 정렬은 일반적으로 그다지 흥미롭지 않으므로 대부분의 관점에서 VirtualAlloc은 4KB 청크에서 작동합니다. 이러한 세부 정보는 작은 VirtualAlloc을 많이 수행하거나 (주소 공간이 부족함) 멋진 작업 (인접하지만 별도의 할당과 같은)을 수행하려는 경우에만 중요합니다.
arx

나는 malloc / new / CRT가 HeapAlloc을 호출 한 다음 자체 알고리즘을 사용하여 HeapAlloc 메모리 블록에서 메모리 블록을 반환한다고 생각 했습니까?
paulm

29

VirtualAllocOS VM (가상 메모리) 시스템의 특수 할당입니다. VM 시스템의 할당은 아키텍처에 따라 달라지는 할당 단위 (할당 단위)로 이루어져야합니다. VM 시스템의 할당은 메모리 할당의 가장 기본적인 형태 중 하나입니다. VM 할당은 여러 형태를 취할 수 있으며, 메모리가 반드시 RAM에 전용되거나 물리적으로 백업되는 것은 아닙니다 (그럴 수 있음). VM 할당은 일반적으로 할당해야하는 특수 목적 유형의 할당입니다.

  • 매우 크고
  • 공유해야합니다.
  • 특정 값 (성능 이유)에 따라 정렬되어야합니다.
  • 발신자는이 모든 메모리를 한 번에 사용할 필요가 없습니다.
  • 기타...

HeapAlloc무엇을 본질적으로 malloc하고 new모두가 결국 호출합니다. 범용 할당의 다양한 유형의 시나리오에서 매우 빠르고 사용 가능하도록 설계되었습니다. 고전적인 의미의 "힙"입니다. 힙은 실제로 OS에서 할당 공간 VirtualAlloc처음 예약 하는 데 사용되는에 의해 설정됩니다 . 에 의해 공간이 초기화 된 VirtualAlloc후 다양한 테이블, 목록 및 기타 데이터 구조가 구성되어 HEAP의 작동을 유지하고 제어합니다. 이러한 작업 중 일부는 힙의 크기를 동적으로 조정 (증가 및 축소)하여 특정 용도 (일부 크기의 빈번한 할당) 등에 힙을 조정하는 형태입니다.

new그리고 malloc다소 동일하며 malloc본질적으로에 대한 정확한 호출입니다 HeapAlloc( heap-id-default ). new그러나 [추가적으로] C ++ 객체에 할당 된 메모리를 구성 할 수 있습니다 . 주어진 객체에 대해 C ++는 각 호출자의 힙에 vtables를 저장합니다. 이러한 vtable은 실행을위한 리디렉션이며 상속, 함수 오버로딩 등과 같은 OO 특성을 C ++에 제공하는 요소의 일부를 구성합니다.

_alloca()및 같은 다른 일반적인 할당 방법 _malloca()스택 기반입니다. FileMappings는 실제로 VirtualAlloc해당 매핑을 유형으로 지정하는 특정 비트 플래그로 할당 되고 설정됩니다 FILE.

대부분의 경우 해당 메모리 사용과 일치하는 방식으로 메모리를 할당해야합니다. newC ++, mallocC, VirtualAlloc대규모 또는 IPC의 경우.

*** 참고로,에서 수행 한 대용량 메모리 할당 HeapAlloc은 실제로 VirtualAlloc일정 크기 (몇 백 k 또는 16MB 또는 내가 잊은 것이지만 상당히 큽니다 :) 이후로 배송됩니다 .

*** 편집 나는 IPC에 대해 간략히 언급했으며이 질문에 대한 응답자 중 누구도 논의하지 않은 VirtualAlloc관련 항목에 대해 매우 깔끔한 VirtualAlloc것도 있습니다.

VirtualAllocEx 는 한 프로세스가 다른 프로세스 의 주소 공간에 메모리를 할당하는 데 사용할 수있는 것입니다. 가장 일반적으로 이것은 CreateRemoteThread 를 통해 다른 프로세스의 컨텍스트에서 원격 실행을 얻기 위해 조합 하여 사용 됩니다 ( , 스레드는 다른 프로세스에서 실행 됨).CreateThread


29

메모리 관리가 필요한 언어 (예 : C 또는 C ++)를 사용하려는 경우 메모리 할당 API (Windows)의 차이점을 이해하는 것이 매우 중요합니다. IMHO를 설명하는 가장 좋은 방법은 다이어그램을 사용하는 것입니다.

여기에 이미지 설명 입력

이것은 매우 단순화 된 Windows 관련보기입니다.

이 다이어그램을 이해하는 방법은 다이어그램에서 메모리 할당 방법이 높을수록 더 높은 수준의 구현을 사용한다는 것입니다. 그러나 바닥부터 시작합시다.

커널 모드 메모리 관리자

운영 체제에 대한 모든 메모리 예약 및 할당은 물론 메모리 매핑 된 파일 , 공유 메모리 , 쓰기복사 작업 등을 지원합니다. 사용자 모드 코드에서 직접 액세스 할 수 없으므로 건너 뛰겠습니다. 여기.

VirtualAlloc / VirtualFree

사용자 모드 에서 사용할 수 있는 가장 낮은 수준의 API 입니다. 이 함수는 기본적으로 ZwAllocateVirtualMemory 를 호출 하여 빠른 시스템 호출 을 수행 하여 추가 처리를 커널 메모리 관리자에 맡깁니다 . 또한 사용자 모드에서 사용 가능한 모든 메모리에서 새 메모리 블록을 예약 / 할당하는 가장 빠른 방법입니다.VirtualAllocring0

그러나 두 가지 주요 조건이 있습니다.

  • 시스템 단위 경계에 정렬 된 메모리 블록 만 할당합니다.

  • 시스템 단위의 배수 인 크기의 메모리 블록 만 할당합니다.

그렇다면이 시스템 세분성 은 무엇 입니까? GetSystemInfo 를 호출하여 얻을 수 있습니다 . dwAllocationGranularity매개 변수 로 리턴됩니다 . 그 값은 구현 (및 하드웨어 가능)에 따라 다르지만 많은 64 비트 Windows 시스템에서는 0x10000바이트 또는 64K.

따라서 이것이 의미하는 바는 VirtualAlloc다음 과 같이 8 바이트 메모리 블록을 할당하려는 경우입니다 .

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

성공 pAddress하면 0x10000바이트 경계 에 정렬됩니다 . 그리고 8 바이트 만 요청 했음에도 불구하고 얻을 실제 메모리 블록은 전체 page(또는 4K바이트 와 같은 것 입니다. 정확한 페이지 크기가 dwPageSize매개 변수에 반환됩니다 .) 그러나 그 위에 전체 메모리 블록이 스패닝 0x10000바이트 (또는 64K대부분의 경우)는 추가 할당에 사용할 수 pAddress 없습니다 . 따라서 어떤 의미에서 8 바이트를 할당하면 65536을 요청할 수도 있습니다.

따라서 여기서 이야기의 교훈은 VirtualAlloc응용 프로그램의 일반적인 메모리 할당 을 대체하지 않는 것 입니다. 아래 과 같이 매우 특정한 경우에 사용해야합니다 . (보통 큰 메모리 블록을 예약 / 할당하는 데 사용됩니다.)

VirtualAlloc잘못 사용하면 심각한 메모리 조각화가 발생할 수 있습니다.

HeapCreate / HeapAlloc / HeapFree / HeapDestroy

간단히 말해서 함수는 기본적으로 함수의 래퍼입니다 VirtualAlloc. 여기에있는 다른 답변은 그것에 대한 꽤 좋은 개념을 제공합니다. 매우 단순한 관점에서 힙이 작동 하는 방식 은 다음과 같습니다.

  • HeapCreateVirtualAlloc내부적으로 (또는 ZwAllocateVirtualMemory구체적으로) 호출하여 대규모 가상 메모리 블록을 예약합니다 . 또한 예약 된 가상 메모리 블록 내에서 더 작은 크기 할당을 추적 할 수있는 내부 데이터 구조를 설정합니다.

  • 어느 통화 HeapAllocHeapFree실제로 (의 코스 요청이 이미 예약 된 것을 초과하지 않는 한 / 새로운 메모리를 할당하지 않는 HeapCreate) 대신 그들은 미터 밖으로 (또는 commit작은 메모리 블록으로 해부하여) 이전에 예약 된 큰 덩어리, 그 사용자 요청.

  • HeapDestroy차례로 VirtualFree실제로 가상 메모리를 해제하는 호출 .

따라서이 모든 것이 함수를 애플리케이션의 일반 메모리 할당에 대한 완벽한 후보로 만듭니다 . 임의의 크기 메모리 할당에 적합합니다. 그러나 함수 의 편리함을 위해 지불하는 작은 대가 는 VirtualAlloc더 큰 메모리 블록을 예약 할 때 약간의 오버 헤드가 발생한다는 것 입니다.

힙의 또 다른 좋은 점은 실제로 만들 필요가 없다는 것입니다. 일반적으로 프로세스가 시작될 때 생성됩니다. 따라서 GetProcessHeap 함수 를 호출하여 액세스 할 수 있습니다 .

malloc / 무료

함수에 대한 언어 별 래퍼입니다 . 달리 HeapAlloc, HeapFree코드가 다른 운영 체제는 Windows 용으로 컴파일하지만, 경우 등 이러한 기능뿐만 아니라 작동합니다 (등 리눅스 등)

이것은 C로 프로그래밍하는 경우 메모리를 할당 / 비우기 위해 권장되는 방법입니다. (특정 커널 모드 장치 드라이버를 코딩하지 않는 한)

신규 / 삭제

A와 이리 높은 수준 (물론,에 대한 C++) 메모리 관리 연산자. 그들은을위한 특정 C++언어, 같은 malloc대한 C, 또한 대한 래퍼 heap기능. 또한 C++생성자의 특정 초기화, 소멸자 할당 해제, 예외 발생 등 을 처리하는 자체 코드가 많이 있습니다 .

이러한 함수는에서 프로그래밍하는 경우 메모리 및 개체를 할당 / 해제하는 데 권장되는 방법입니다 C++.


마지막으로, VirtualAlloc프로세스간에 메모리를 공유 하는 데 사용 하는 것에 대한 다른 응답에서 언급 한 내용에 대해 한 가지 언급하고 싶습니다 . VirtualAlloc그 자체로는 예약 / 할당 된 메모리를 다른 프로세스와 공유 할 수 없습니다. 이를 위해서는 CreateFileMapping다른 프로세스와 공유 할 수있는 명명 된 가상 메모리 블록을 생성 할 수있는 API 를 사용해야 합니다. 또한 읽기 / 쓰기 액세스를 위해 디스크의 파일을 가상 메모리에 매핑 할 수 있습니다. 그러나 그것은 또 다른 주제입니다.


7

개요 :

  • VirtualAlloc, HeapAlloc 등은 OS에서 직접 다양한 유형의 메모리를 할당하는 Windows API입니다. VirtualAlloc은 Windows 가상 메모리 시스템의 페이지를 관리하는 반면 HeapAlloc은 특정 OS 힙에서 할당합니다. 솔직히, 당신은 그들 중 하나를 사용할 필요가 없을 것입니다.

  • malloc은 프로세스에 메모리를 할당하는 표준 C (및 C ++) 라이브러리 함수입니다. malloc의 구현은 일반적으로 OS API 중 하나를 사용하여 앱이 시작될 때 메모리 풀을 만든 다음 malloc 요청을 할 때 할당합니다.

  • new는 메모리를 할당 한 다음 해당 메모리에서 생성자를 적절하게 호출하는 표준 C ++ 연산자입니다. malloc 또는 OS API 측면에서 구현 될 수 있으며,이 경우에도 일반적으로 애플리케이션 시작시 메모리 풀을 생성합니다.



2

VirtualAlloc=> 가상 메모리에 직접 할당하고 블록 단위로 예약 / 커밋합니다. 이는 대규모 할당 (예 : 대규모 배열)에 적합합니다.

HeapAlloc/ new=>는 기본 힙 (또는 생성 할 수있는 다른 힙)에 메모리를 할당합니다. 이것은 개체별로 할당되며 작은 개체에 적합합니다. 기본 힙은 직렬화 가능하므로 스레드 할당이 보장됩니다 (이로 인해 고성능 시나리오에서 몇 가지 문제가 발생할 수 있으므로 자체 힙을 만들 수 있습니다).

malloc=>는 유사한 C 런타임 힙을 사용 HeapAlloc하지만 호환성 시나리오에서 일반적입니다.

간단히 말해서 힙은 원시 가상 메모리가 아니라 힙 관리자가 관리하는 가상 메모리 덩어리입니다.

메모리 세계의 마지막 모델은 메모리 매핑 파일입니다.이 시나리오는 대용량 데이터 청크 (예 : 대용량 파일)에 적합합니다. 이것은 EXE를 열 때 내부적으로 사용됩니다 (메모리에 EXE를로드하지 않고 메모리 매핑 파일 만 생성 함).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.