What's the differences between VirtualAlloc and HeapAlloc?
Each API is for different uses. Each one also requires that you use the correct deallocation/freeing function when you're done with the memory.
VirtualAlloc
A low-level, Windows API that provides lots of options, but is mainly useful for people in fairly specific situations. Can only allocate memory in (edit: not 4KB) larger chunks. There are situations where you need it, but you'll know when you're in one of these situations. One of the most common is if you have to share memory directly with another process. Don't use it for general-purpose memory allocation. Use VirtualFree
to deallocate.
HeapAlloc
Allocates whatever size of memory you ask for, not in big chunks than VirtualAlloc
. HeapAlloc
knows when it needs to call VirtualAlloc
and does so for you automatically. Like malloc
, but is Windows-only, and provides a couple more options. Suitable for allocating general chunks of memory. Some Windows APIs may require that you use this to allocate memory that you pass to them, or use its companion HeapFree
to free memory that they return to you.
malloc
The C way of allocating memory. Prefer this if you are writing in C rather than C++, and you want your code to work on e.g. Unix computers too, or someone specifically says that you need to use it. Doesn't initialise the memory. Suitable for allocating general chunks of memory, like HeapAlloc
. A simple API. Use free
to deallocate. Visual C++'s malloc
calls HeapAlloc
.
new
The C++ way of allocating memory. Prefer this if you are writing in C++. It puts an object or objects into the allocated memory, too. Use delete
to deallocate (or delete[]
for arrays). Visual studio's new
calls HeapAlloc
, and then maybe initialises the objects, depending on how you call it.
In recent C++ standards (C++11 and above), if you have to manually use delete
, you're doing it wrong and should use a smart pointer like unique_ptr
instead. From C++14 onwards, the same can be said of new
(replaced with functions such as make_unique()
).
There are also a couple of other similar functions like SysAllocString
that you may be told you have to use in specific circumstances.
It is very important to understand the distinction between memory allocation APIs (in Windows) if you plan on using a language that requires memory management (like C or C++.) And the best way to illustrate it IMHO is with a diagram:
Note that this is a very simplified, Windows-specific view.
The way to understand this diagram is that the higher on the diagram a memory allocation method is, the higher level implementation it uses. But let's start from the bottom.
Kernel-Mode Memory Manager
It provides all memory reservations & allocations for the operating system, as well as support for memory-mapped files, shared memory, copy-on-write operations, etc. It's not directly accessible from the user-mode code, so I'll skip it here.
VirtualAlloc / VirtualFree
These are the lowest level APIs available from the user mode. The VirtualAlloc
function basically invokes ZwAllocateVirtualMemory that in turn does a quick syscall to ring0
to relegate further processing to the kernel memory manager. It is also the fastest method to reserve/allocate block of new memory from all available in the user mode.
But it comes with two main conditions:
It only allocates memory blocks aligned on the system granularity boundary.
It only allocates memory blocks of the size that is the multiple of the system granularity.
So what is this system granularity? You can get it by calling GetSystemInfo. It is returned as the dwAllocationGranularity
parameter. Its value is implementation (and possibly hardware) specific, but on many 64-bit Windows systems it is set at 0x10000
bytes, or 64K
.
So what all this means, is that if you try to allocate, say just an 8 byte memory block with VirtualAlloc
:
void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
If successful, pAddress
will be aligned on the 0x10000
byte boundary. And even though you requested only 8 bytes, the actual memory block that you will get will be the entire page
(or, something like 4K
bytes. The exact page size is returned in the dwPageSize
parameter.) But, on top of that, the entire memory block spanning 0x10000
bytes (or 64K
in most cases) from pAddress
will not be available for any further allocations. So in a sense, by allocating 8 bytes you could as well be asking for 65536.
So the moral of the story here is not to substitute VirtualAlloc
for generic memory allocations in your application. It must be used for very specific cases, as is done with the heap below. (Usually for reserving/allocating large blocks of memory.)
Using VirtualAlloc
incorrectly can lead to severe memory fragmentation.
HeapCreate / HeapAlloc / HeapFree / HeapDestroy
In a nutshell, the heap functions are basically a wrapper for VirtualAlloc
function. Other answers here provide a pretty good concept of it. I'll add that, in a very simplistic view, the way heap works is this:
HeapCreate
reserves a large block of virtual memory by callingVirtualAlloc
internally (orZwAllocateVirtualMemory
to be specific). It also sets up an internal data structure that can track further smaller size allocations within the reserved block of virtual memory.Any calls to
HeapAlloc
andHeapFree
do not actually allocate/free any new memory (unless, of course the request exceeds what has been already reserved inHeapCreate
) but instead they meter out (orcommit
) a previously reserved large chunk, by dissecting it into smaller memory blocks that a user requests.HeapDestroy
in turn callsVirtualFree
that actually frees the virtual memory.
So all this makes heap functions perfect candidates for generic memory allocations in your application. It is great for arbitrary size memory allocations. But a small price to pay for the convenience of the heap functions is that they introduce a slight overhead over VirtualAlloc
when reserving larger blocks of memory.
Another good thing about heap is that you don't really need to create one. It is generally created for you when your process starts. So one can access it by calling GetProcessHeap function.
malloc / free
Is a language-specific wrapper for the heap functions. Unlike HeapAlloc
, HeapFree
, etc. these functions will work not only if your code is compiled for Windows, but also for other operating systems (such as Linux, etc.)
This is a recommended way to allocate/free memory if you program in C. (Unless, you're coding a specific kernel mode device driver.)
new / delete
Come as a high level (well, for C++
) memory management operators. They are specific for the C++
language, and like malloc
for C
, are also the wrappers for the heap
functions. They also have a whole bunch of their own code that deals C++
-specific initialization of constructors, deallocation in destructors, raising an exception, etc.
These functions are a recommended way to allocate/free memory and objects if you program in C++
.
Lastly, one comment I want to make about what has been said in other responses about using VirtualAlloc
to share memory between processes. VirtualAlloc
by itself does not allow sharing of its reserved/allocated memory with other processes. For that one needs to use CreateFileMapping
API that can create a named virtual memory block that can be shared with other processes. It can also map a file on disk into virtual memory for read/write access. But that is another topic.
VirtualAlloc
is a specialized allocation of the OS virtual memory (VM) system. Allocations in the VM system must be made at an allocation granularity which (the allocation granularity) is architecture dependent. Allocation in the VM system is one of the most basic forms of memory allocation. VM allocations can take several forms, memory is not necessarily dedicated or physically backed in RAM (though it can be). VM allocation is typically a special purpose type of allocation, either because of the allocation has to
- be very large,
- needs to be shared,
- must be aligned on a particular value (performance reasons) or
- the caller need not use all of this memory at once...
- etc...
HeapAlloc
is essentially what malloc
and new
both eventually call. It is designed to be very fast and usable under many different types of scenarios of a general purpose allocation. It is the "Heap" in a classic sense. Heaps are actually setup by a VirtualAlloc
, which is what is used to initially reserve allocation space from the OS. After the space is initialized by VirtualAlloc
, various tables, lists and other data structures are configured to maintain and control the operation of the HEAP. Some of that operation is in the form of dynamically sizing (growing and shrinking) the heap, adapting the heap to particular usages (frequent allocations of some size), etc..
new
and malloc
are somewhat the same, malloc
is essentially an exact call into HeapAlloc( heap-id-default )
; new
however, can [additionally] configure the allocated memory for C++ objects. For a given object, C++ will store vtables on the heap for each caller. These vtables are redirects for execution and form part of what gives C++ it's OO characteristics like inheritance, function overloading, etc...
Some other common allocation methods like _alloca()
and _malloca()
are stack based; FileMappings are really allocated with VirtualAlloc
and set with particular bit flags which designate those mappings to be of type FILE
.
Most of the time, you should allocate memory in a way which is consistent with the use of that memory ;). new
in C++, malloc
for C, VirtualAlloc
for massive or IPC cases.
*** Note, large memory allocations done by HeapAlloc
are actually shipped off to VirtualAlloc
after some size (couple hundred k or 16 MB or something I forget, but fairly big :) ).
*** EDIT
I briefly remarked about IPC and VirtualAlloc
, there is also something very neat about a related VirtualAlloc
which none of the responders to this question have discussed.
VirtualAlloc
Ex is what one process can use to allocate memory in an address space of a different process. Most typically, this is used in combination to get remote execution in the context of another process via CreateRemoteThread (similar to CreateThread
, the thread is just run in the other process).