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

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

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



답변

각 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특정 상황에서 사용해야하는 것과 같은 몇 가지 다른 유사한 기능도 있습니다.


답변

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


답변

메모리 관리가 필요한 언어 (예 : 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 를 사용해야 합니다. 또한 읽기 / 쓰기 액세스를 위해 디스크의 파일을 가상 메모리에 매핑 할 수 있습니다. 그러나 그것은 또 다른 주제입니다.


답변

개요 :

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

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

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


답변

VirtualAlloc===> sbrk()UNIX에서

HeapAlloc====> malloc()UNIX에서


답변

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

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

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

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

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


답변