64BitAllocDebugger.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /* Copyright The kNet Project.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License. */
  11. /** @file 64BitAllocDebugger.cpp
  12. @brief Virtually reserves all memory on Windows in the < 4GB memory area so that all
  13. pointers used by the application are outside the 32-bit range.
  14. Idea and code taken from http://randomascii.wordpress.com/2012/02/14/64-bit-made-easy/ */
  15. #ifdef _WIN64
  16. #include "kNet/64BitAllocDebugger.h"
  17. #include <stdio.h>
  18. #include <windows.h>
  19. #include <vector>
  20. BottomMemoryAllocator::BottomMemoryAllocator()
  21. {
  22. ReserveBottomMemory();
  23. }
  24. BottomMemoryAllocator::~BottomMemoryAllocator()
  25. {
  26. FreeBottomMemory();
  27. }
  28. void BottomMemoryAllocator::ReserveBottomMemory()
  29. {
  30. static bool s_initialized = false;
  31. if ( s_initialized )
  32. return;
  33. s_initialized = true;
  34. // Start by reserving large blocks of address space, and then
  35. // gradually reduce the size in order to capture all of the
  36. // fragments. Technically we should continue down to 64 KB but
  37. // stopping at 1 MB is sufficient to keep most allocators out.
  38. const size_t LOW_MEM_LINE = 0x100000000LL;
  39. size_t totalReservation = 0;
  40. size_t numVAllocs = 0;
  41. size_t numHeapAllocs = 0;
  42. size_t oneMB = 1024 * 1024;
  43. for (size_t size = 256 * oneMB; size >= oneMB; size /= 2)
  44. {
  45. for (;;)
  46. {
  47. void* p = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
  48. if (!p)
  49. break;
  50. if ((size_t)p >= LOW_MEM_LINE)
  51. {
  52. // We don't need this memory, so release it completely.
  53. VirtualFree(p, 0, MEM_RELEASE);
  54. break;
  55. }
  56. totalReservation += size;
  57. ++numVAllocs;
  58. virtualAllocated.push_back(p);
  59. }
  60. }
  61. // Now repeat the same process but making heap allocations, to use up
  62. // the already reserved heap blocks that are below the 4 GB line.
  63. HANDLE heap = GetProcessHeap();
  64. for (size_t blockSize = 64 * 1024; blockSize >= 16; blockSize /= 2)
  65. {
  66. for (;;)
  67. {
  68. void* p = HeapAlloc(heap, 0, blockSize);
  69. if (!p)
  70. break;
  71. if ((size_t)p >= LOW_MEM_LINE)
  72. {
  73. // We don't need this memory, so release it completely.
  74. HeapFree(heap, 0, p);
  75. break;
  76. }
  77. totalReservation += blockSize;
  78. ++numHeapAllocs;
  79. heapAllocated.push_back(p);
  80. }
  81. }
  82. // Perversely enough the CRT doesn't use the process heap. Suck up
  83. // the memory the CRT heap has already reserved.
  84. for (size_t blockSize = 64 * 1024; blockSize >= 16; blockSize /= 2)
  85. {
  86. for (;;)
  87. {
  88. void* p = malloc(blockSize);
  89. if (!p)
  90. break;
  91. if ((size_t)p >= LOW_MEM_LINE)
  92. {
  93. // We don't need this memory, so release it completely.
  94. free(p);
  95. break;
  96. }
  97. totalReservation += blockSize;
  98. ++numHeapAllocs;
  99. mallocAllocated.push_back(p);
  100. }
  101. }
  102. // Print diagnostics showing how many allocations we had to make in
  103. // order to reserve all of low memory, typically less than 200.
  104. printf("Reserved %1.3f MB (%d vallocs,"
  105. "%d heap allocs) of low-memory.\n",
  106. totalReservation / (1024 * 1024.0),
  107. (int)numVAllocs, (int)numHeapAllocs);
  108. }
  109. void BottomMemoryAllocator::FreeBottomMemory()
  110. {
  111. for(size_t i = 0; i < virtualAllocated.size(); ++i)
  112. VirtualFree(virtualAllocated[i], 0, MEM_RELEASE);
  113. HANDLE heap = GetProcessHeap();
  114. for(size_t i = 0; i < heapAllocated.size(); ++i)
  115. HeapFree(heap, 0, heapAllocated[i]);
  116. for(size_t i = 0; i < mallocAllocated.size(); ++i)
  117. free(mallocAllocated[i]);
  118. }
  119. #endif