アロケータ置換
仮想メモリ2GBの壁が問題になった。環境上 /3GB も使えない。冷やし中華さんはこう考えた。
「2GB以上のメモリは確保できない。ならメモリの確保はすべてメモリマップトファイルにしてしまえ」
試行段階としてvc9test20071228.cpp.txtを書いてみた。このコードはHeapAllocをCreateFileMapping & MapViewOfFileExの組み合わせ、要するにヒープ確保をメモリマップトファイル作成に置き換える。
static LPVOID WINAPI NewHeapAlloc( __in HANDLE hHeap, __in DWORD dwFlags, __in SIZE_T dwBytes ) { void* result = NULL; LARGE_INTEGER l = { dwBytes }; TCHAR tmpname[MAX_PATH]; if (!::GetTempFileName(_T("."), _T("mm_"), 0, tmpname)) goto FAIL; HANDLE hFile = ::CreateFile(tmpname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL); if (hFile == INVALID_HANDLE_VALUE) goto FAIL; HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, l.HighPart, l.LowPart, NULL); result = ::MapViewOfFileEx(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL); return result; FAIL: ::SetLastError(STATUS_NO_MEMORY); return NULL; // return OldHeapAlloc(hHeap, dwFlags, dwBytes); }
結論としてこの目論見は失敗なのだが、メモリマップトファイルは毎回ユニークなファイル名でCreateFileされるなど、結構面白いことができるものだと思った。
もっとも、ハンドルを開放しないことや、HeapFreeをUnmapViewOfFileに置換していないことなど、見て判るバグがあり、このままの実装の場合、致命的なバグとしてNewHeapAllocの実装の中でスタックオーバーフローが発生する。
GetTempFileNameおよびCreateFileは内部でRtlInitUnicodeStringExを呼ぶ。RtlInitUnicodeStringExは内部でRtlAllocateHeapを呼ぶらしく、結果再帰する。