MapViewOfFile() works without any problem if our process has not hit the 2GB limit yet. However if the process hits the limit then MapViewOfFile() no longer works even if some or all of the memory is deallocated. GetLastError() returns 8, which means ERROR_NOT_ENOUGH_MEMORY, Not enough storage is available to process this command
. Here is a small program showing the problem:
#include <Windows.h>
#include <cstdio>
#include <vector>
const int sizeOfTheFileMappingObject = 20;
const int numberOfBytesToMap = sizeOfTheFileMappingObject;
const char* fileMappingObjectName = "Global\\QWERTY";
void Allocate2GBMemoryWithMalloc(std::vector<void*>* addresses)
{
const size_t sizeOfMemAllocatedAtOnce = 32 * 1024;
for (;;) {
void* address = malloc(sizeOfMemAllocatedAtOnce);
if (address != NULL) {
addresses->push_back(address);
}
else {
printf("The %dth malloc() returned NULL. Allocated memory: %d MB\n",
addresses->size() + 1,
(addresses->size() * sizeOfMemAllocatedAtOnce) / (1024 * 1024));
break;
}
}
}
void DeallocateMemoryWithFree(std::vector<void*>* addresses)
{
std::vector<void*>::iterator current = addresses->begin();
std::vector<void*>::iterator end = addresses->end();
for (; current != end; ++current) {
free(*current);
}
addresses->clear();
printf("Memory is deallocated.\n");
}
void TryToMapViewOfFile()
{
HANDLE fileMapping = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE,
fileMappingObjectName);
if (fileMapping == NULL) {
printf("OpenFileMapping() failed. LastError: %d\n", GetLastError());
return;
}
LPVOID mappedView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0,
numberOfBytesToMap);
if (mappedView == NULL) {
printf("MapViewOfFile() failed. LastError: %d\n", GetLastError());
if (!CloseHandle(fileMapping)) {
printf("CloseHandle() failed. LastError: %d\n", GetLastError());
}
return;
}
if (!UnmapViewOfFile(mappedView)) {
printf("UnmapViewOfFile() failed. LastError: %d\n", GetLastError());
if (!CloseHandle(fileMapping)) {
printf("CloseHandle() failed. LastError: %d\n", GetLastError());
}
return;
}
if (!CloseHandle(fileMapping)) {
printf("CloseHandle() failed. LastError: %d\n", GetLastError());
return;
}
printf("MapViewOfFile() succeeded.\n");
}
int main(int argc, char* argv[])
{
HANDLE fileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, sizeOfTheFileMappingObject, fileMappingObjectName);
if (fileMapping == NULL) {
printf("CreateFileMapping() failed. LastError: %d\n", GetLastError());
return -1;
}
TryToMapViewOfFile();
std::vector<void*> addresses;
Allocate2GBMemoryWithMalloc(&addresses);
TryToMapViewOfFile();
DeallocateMemoryWithFree(&addresses);
TryToMapViewOfFile();
Allocate2GBMemoryWithMalloc(&addresses);
DeallocateMemoryWithFree(&addresses);
if (!CloseHandle(fileMapping)) {
printf("CloseHandle() failed. LastError: %d\n", GetLastError());
}
return 0;
}
The output of the program:
MapViewOfFile() succeeded.
The 65126th malloc() returned NULL. Allocated memory: 2035 MB
MapViewOfFile() failed. LastError: 8
Memory is deallocated.
MapViewOfFile() failed. LastError: 8
The 64783th malloc() returned NULL. Allocated memory: 2024 MB
Memory is deallocated.
As you can see MapViewOfFile() fails with 8 even after releasing all memory that was allocated. Even though MapViewOfFile() reports ERROR_NOT_ENOUGH_MEMORY
we can call malloc() successfully.
We ran this example program on Windows7,32bit; Windows 8.1,32bit and Windows Server 2008 R2,64bit and the results were the same.
So the question is: Why does MapViewOfFile() fail with ERROR_NOT_ENOUGH_MEMORY
after the process hits the 2GB limit?