같은 Windows 환경에서 메모리를 할당하는 방법은 많이있다 VirtualAlloc
, HeapAlloc
, malloc
, new
.
따라서 그들 사이의 차이점은 무엇입니까?
답변:
각 API는 서로 다른 용도로 사용됩니다. 또한 각각은 메모리를 다 사용할 때 올바른 할당 해제 / 해제 기능을 사용해야합니다.
많은 옵션을 제공하지만 주로 특정 상황에있는 사람들에게 유용한 저수준 Windows API입니다. 더 큰 청크 (편집 : 4KB 아님)에만 메모리를 할당 할 수 있습니다. 필요한 상황이 있지만 이러한 상황 중 하나에 해당하는 경우 알 수 있습니다. 가장 일반적인 방법 중 하나는 다른 프로세스와 직접 메모리를 공유해야하는 경우입니다. 범용 메모리 할당에는 사용하지 마십시오. VirtualFree
할당을 해제하는 데 사용 합니다.
원하는 크기의 메모리를 할당합니다 VirtualAlloc
.. HeapAlloc
전화 VirtualAlloc
가 필요한시기를 알고 자동으로 수행합니다. 과 유사 malloc
하지만 Windows 전용이며 몇 가지 추가 옵션을 제공합니다. 일반적인 메모리 청크 할당에 적합합니다. 일부 Windows API에서는이를 사용하여 전달한 메모리를 할당하거나 해당 동반자 HeapFree
를 사용하여 반환되는 메모리를 해제해야 할 수 있습니다.
메모리를 할당하는 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
특정 상황에서 사용해야하는 것과 같은 몇 가지 다른 유사한 기능도 있습니다.
VirtualAlloc
OS 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
.
대부분의 경우 해당 메모리 사용과 일치하는 방식으로 메모리를 할당해야합니다. new
C ++, malloc
C, VirtualAlloc
대규모 또는 IPC의 경우.
*** 참고로,에서 수행 한 대용량 메모리 할당 HeapAlloc
은 실제로 VirtualAlloc
일정 크기 (몇 백 k 또는 16MB 또는 내가 잊은 것이지만 상당히 큽니다 :) 이후로 배송됩니다 .
*** 편집 나는 IPC에 대해 간략히 언급했으며이 질문에 대한 응답자 중 누구도 논의하지 않은 VirtualAlloc
관련 항목에 대해 매우 깔끔한 VirtualAlloc
것도 있습니다.
VirtualAlloc
Ex 는 한 프로세스가 다른 프로세스 의 주소 공간에 메모리를 할당하는 데 사용할 수있는 것입니다. 가장 일반적으로 이것은 CreateRemoteThread 를 통해 다른 프로세스의 컨텍스트에서 원격 실행을 얻기 위해 조합 하여 사용 됩니다 ( , 스레드는 다른 프로세스에서 실행 됨).CreateThread
메모리 관리가 필요한 언어 (예 : C 또는 C ++)를 사용하려는 경우 메모리 할당 API (Windows)의 차이점을 이해하는 것이 매우 중요합니다. IMHO를 설명하는 가장 좋은 방법은 다이어그램을 사용하는 것입니다.
이것은 매우 단순화 된 Windows 관련보기입니다.
이 다이어그램을 이해하는 방법은 다이어그램에서 메모리 할당 방법이 높을수록 더 높은 수준의 구현을 사용한다는 것입니다. 그러나 바닥부터 시작합시다.
운영 체제에 대한 모든 메모리 예약 및 할당은 물론 메모리 매핑 된 파일 , 공유 메모리 , 쓰기 시 복사 작업 등을 지원합니다. 사용자 모드 코드에서 직접 액세스 할 수 없으므로 건너 뛰겠습니다. 여기.
사용자 모드 에서 사용할 수 있는 가장 낮은 수준의 API 입니다. 이 함수는 기본적으로 ZwAllocateVirtualMemory 를 호출 하여 빠른 시스템 호출 을 수행 하여 추가 처리를 커널 메모리 관리자에 맡깁니다 . 또한 사용자 모드에서 사용 가능한 모든 메모리에서 새 메모리 블록을 예약 / 할당하는 가장 빠른 방법입니다.VirtualAlloc
ring0
그러나 두 가지 주요 조건이 있습니다.
시스템 단위 경계에 정렬 된 메모리 블록 만 할당합니다.
시스템 단위의 배수 인 크기의 메모리 블록 만 할당합니다.
그렇다면이 시스템 세분성 은 무엇 입니까? 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
잘못 사용하면 심각한 메모리 조각화가 발생할 수 있습니다.
간단히 말해서 힙 함수는 기본적으로 함수의 래퍼입니다 VirtualAlloc
. 여기에있는 다른 답변은 그것에 대한 꽤 좋은 개념을 제공합니다. 매우 단순한 관점에서 힙이 작동 하는 방식 은 다음과 같습니다.
HeapCreate
VirtualAlloc
내부적으로 (또는 ZwAllocateVirtualMemory
구체적으로) 호출하여 대규모 가상 메모리 블록을 예약합니다 . 또한 예약 된 가상 메모리 블록 내에서 더 작은 크기 할당을 추적 할 수있는 내부 데이터 구조를 설정합니다.
어느 통화 HeapAlloc
와 HeapFree
실제로 (의 코스 요청이 이미 예약 된 것을 초과하지 않는 한 / 새로운 메모리를 할당하지 않는 HeapCreate
) 대신 그들은 미터 밖으로 (또는 commit
작은 메모리 블록으로 해부하여) 이전에 예약 된 큰 덩어리, 그 사용자 요청.
HeapDestroy
차례로 VirtualFree
실제로 가상 메모리를 해제하는 호출 .
따라서이 모든 것이 힙 함수를 애플리케이션의 일반 메모리 할당에 대한 완벽한 후보로 만듭니다 . 임의의 크기 메모리 할당에 적합합니다. 그러나 힙 함수 의 편리함을 위해 지불하는 작은 대가 는 VirtualAlloc
더 큰 메모리 블록을 예약 할 때 약간의 오버 헤드가 발생한다는 것 입니다.
힙의 또 다른 좋은 점은 실제로 만들 필요가 없다는 것입니다. 일반적으로 프로세스가 시작될 때 생성됩니다. 따라서 GetProcessHeap 함수 를 호출하여 액세스 할 수 있습니다 .
힙 함수에 대한 언어 별 래퍼입니다 . 달리 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
=> 가상 메모리에 직접 할당하고 블록 단위로 예약 / 커밋합니다. 이는 대규모 할당 (예 : 대규모 배열)에 적합합니다.
HeapAlloc
/ new
=>는 기본 힙 (또는 생성 할 수있는 다른 힙)에 메모리를 할당합니다. 이것은 개체별로 할당되며 작은 개체에 적합합니다. 기본 힙은 직렬화 가능하므로 스레드 할당이 보장됩니다 (이로 인해 고성능 시나리오에서 몇 가지 문제가 발생할 수 있으므로 자체 힙을 만들 수 있습니다).
malloc
=>는 유사한 C 런타임 힙을 사용 HeapAlloc
하지만 호환성 시나리오에서 일반적입니다.
간단히 말해서 힙은 원시 가상 메모리가 아니라 힙 관리자가 관리하는 가상 메모리 덩어리입니다.
메모리 세계의 마지막 모델은 메모리 매핑 파일입니다.이 시나리오는 대용량 데이터 청크 (예 : 대용량 파일)에 적합합니다. 이것은 EXE를 열 때 내부적으로 사용됩니다 (메모리에 EXE를로드하지 않고 메모리 매핑 파일 만 생성 함).