이는 Memory Fragmentation 현상으로 판단한다. 상당히 자잘한 Memory Alloc이 셀 수 없이 반복되면서 메모리 조각화가 발생하는 것이다. 간혹, 큰 메모리 덩어리가 할당/해제 되기도 하고 그러면서 메모리 조각화는 더 할당 받을 수 있는 free 영역이 있음에도 불구하고 !address를Check해보면, 연속된 여분의 메모리 블럭이 존재하지 않아서 OOM을 유발하게끔 한다. 이러한 경우에 일차적으로 할 수 있는 것은 1) 어찌됐든불필요한 작고 많은 memory 조각들이 Leak으로 존재하는 부분을 제거해야만 한다. 이는 DebugDiag의 Leak tracking을 통해서 Checking될 수 있다. DebugDiag에서 제공하는 Leak 분석에서 제공하는 Callstack 정보는 그 메모리 보유 Size가 크지 않더라도 Allocation Count를 Check하여 메모리상에 산재됨으로 인한 Fragmentation의 원인이 되진 않는 지 Check 해볼 수 있다.
2) 두 번째는 문서 http://support.microsoft.com/kb/315407 에서 제공하는 registry key, HeapDecommitFreeBlockThreshold 가 도움이 될 수 있다. 이는 레지스트리에 설정된 값 이상이 되는 경우가 아니면, 재사용을 위해 decommitted 되지 않는 상태로 유지하는 것이다.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager
HeapDecommitFreeBlockThreshold REG_DWORD - 0x00040000 (권고)
3)사실 2번째 방법이 Application을 위해서 얼마나 효율적인지 경험해보진 못했다. 아마도 Windows XP/2003에서 도입된 LFH (Low Fragmentation Heap)을 사용하도록 Application을 구성하는 것이 가장 효율적일지 모르겠다. 이는 문서 http://msdn.microsoft.com/en-us/library/aa366750.aspx 에도 언급되었지만, HeapSetInformation API를 이용해서 HeapCompatibilityInformation(0) 값을 parameter로 전달함으로써 Application Level에서 설정할 수 있다. http://msdn.microsoft.com/en-us/library/aa366705(VS.85).aspx 문서에는 다음과 같은 예제를 확인할 수 있다. 이는 Application에서 사용하는 모든 Heap을 LFH를 사용하도록 설정할 수 있다.
HANDLE heaps[1025];
DWORD nheaps = GetProcessHeaps(1024, heaps);
for (DWORD i = 0; i < nheaps; i++) {
ULONG HeapFragValue = 2;
HeapSetInformation(heaps[i],
HeapCompatibilityInformation,
&HeapFragValue,
sizeof(HeapFragValue));
}
이러한 것들이 Memory Fragmentation을 위해 도움이 될 듯 하다.