MemoryManager.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  1. #include <malloc.h>
  2. #include "MemoryManager.h"
  3. #define MemoryManager_CheckDword 'Good'
  4. #define MemoryManager_MaxPoolSize 96
  5. //Менеджер памяти
  6. dword guardIn[256];
  7. MemoryManager memoryManager;
  8. dword guardOut[256];
  9. //Память для блоков 0 размера
  10. dword MemoryManager::emptyMemory = MemoryManager_CheckDword;
  11. const char * MemoryManager::line = "---------------------------------------------------------------------------------------------";
  12. dword MemoryManager::totalSize = 0;
  13. dword MemoryManager::totalBlocks = 0;
  14. dword MemoryManager::maxBlocks = 0;
  15. dword MemoryManager::maxPoolBlocks = 0;
  16. dword MemoryManager::maxSize = 0;
  17. dword MemoryManager::poolBlocks = 0;
  18. dword MemoryManager::allocsPerFrame = 0;
  19. dword MemoryManager::deletesPerFrame = 0;
  20. dword MemoryManager::maxUsed360 = 0;
  21. MemoryManager::MemoryManager()
  22. {
  23. if((sizeof(MemoryBlock) & 0xf) != 0)
  24. {
  25. throw "Invalidate block size";
  26. }
  27. for(long i = 0; i < ARRSIZE(guardIn); i++)
  28. {
  29. guardIn[i] = MemoryManager_CheckDword + i;
  30. }
  31. for(long i = 0; i < ARRSIZE(guardOut); i++)
  32. {
  33. guardOut[i] = MemoryManager_CheckDword - i;
  34. }
  35. #ifndef MM_NO_DEBUGMEMORY
  36. for(long i = 0; i < sizeof(openBlock.guard)/sizeof(openBlock.guard[0]); i++)
  37. {
  38. openBlock.guard[i] = MemoryManager_CheckDword ^ i;
  39. closeBlock.guard[i] = MemoryManager_CheckDword ^ (rand()*i);
  40. }
  41. descs = null;
  42. descsCount = 0;
  43. descsMax = 0;
  44. currentCheck = 0;
  45. strings = null;
  46. stringsSize = 0;
  47. stringsMax = 0;
  48. for(long i = 0; i < ARRSIZE(entry); i++) entry[i] = -1;
  49. isMemCheck = false;
  50. isPanicCheck = false;
  51. isPanicCheckEnable = false;
  52. #endif
  53. isPoolEnable = false;
  54. lastFileName = null;
  55. lastFileLine = 0;
  56. totalSize = 0;
  57. totalBlocks = 0;
  58. poolBlocks = 0;
  59. maxBlocks = 0;
  60. maxSize = 0;
  61. }
  62. MemoryManager::~MemoryManager()
  63. {
  64. ReleaseMemory(false);
  65. }
  66. void MemoryManager::ReleaseMemory(bool enableLogout)
  67. {
  68. SingleClassThread
  69. #ifndef MM_NO_DEBUGMEMORY
  70. //Освобождение неудалённых блоков
  71. if(enableLogout)
  72. {
  73. if(descsCount > 0)
  74. {
  75. CoreLogOut("%s\nMemory leaks:\n%s\n\n", line, line);
  76. for(long i = 0; i < descsCount; i++)
  77. {
  78. MemoryBlockDesc & d = descs[i];
  79. CoreLogOut(" Pointer: 0x%.8x, size: %u", d.block, d.blockSize);
  80. if(d.descIndex >= 0)
  81. {
  82. DescString & dss = (DescString &)strings[d.descIndex];
  83. CoreLogOut(" File: %s, line: %i", dss.fileName, dss.fileLine);
  84. }
  85. }
  86. CoreLogOut("\n Totoal blocks: %u", descsCount);
  87. }else{
  88. CoreLogOut("Memory manager released successful...");
  89. }
  90. }
  91. //Освободим массив описаний
  92. SysFree(descs);
  93. descs = null;
  94. descsCount = 0;
  95. descsMax = 0;
  96. SysFree(strings);
  97. strings = null;
  98. stringsSize = 0;
  99. stringsMax = 0;
  100. #endif
  101. if(enableLogout)
  102. {
  103. CoreLogOut(" Peak allocate memory blocks: %u", maxBlocks);
  104. if(isPoolEnable) CoreLogOut(" Peak allocate memory blocks in pools: %u, (system blocks = %i)", maxPoolBlocks, maxBlocks - maxPoolBlocks);
  105. CoreLogOut(" Peak allocate memory size: %.2f Mb (%u bytes)", maxSize/1024.0/1024.0, maxSize);
  106. #ifdef _XBOX
  107. CoreLogOut(" Pick memory usages on xbox360 = %.2f Mb (%u bytes)\n", maxUsed360/1024.0/1024.0, maxUsed360);
  108. #endif
  109. CoreLogOut("\n");
  110. }
  111. }
  112. //Изменить объём выделеной памяти
  113. void * MemoryManager::Reallocate(void * ptr, dword size, const char * fileName, long fileLine)
  114. {
  115. #ifndef MM_NO_DEBUGMEMORY
  116. ClassThreadLock
  117. allocsPerFrame++;
  118. //Непрерывная проверка памяти
  119. if(isPanicCheck) SysPanicCheckMemory();
  120. //Сохраним место последнего выделения памяти
  121. lastFileName = fileName;
  122. lastFileLine = fileLine;
  123. //Корректируем указатель
  124. if(ptr)
  125. {
  126. ptr = (MemoryBlock *)ptr - 1;
  127. CheckBlock((MemoryBlock *)ptr);
  128. }else{
  129. totalBlocks++;
  130. if(maxBlocks < totalBlocks) maxBlocks = totalBlocks;
  131. }
  132. #ifdef MM_FILL_MEMORY
  133. dword currentBlockSize = 0;
  134. if(ptr)
  135. {
  136. currentBlockSize = SysSize(ptr);
  137. }
  138. #endif
  139. //Выделяем память с учётом защитных блоков
  140. char * mem = null;
  141. if(isPoolEnable && size + sizeof(MemoryBlock) + sizeof(GuardBlock) <= MemoryManager_MaxPoolSize)
  142. {
  143. mem = (char *)PoolAlloc(size + sizeof(MemoryBlock) + sizeof(GuardBlock), ptr, fileName, fileLine);
  144. }else{
  145. mem = (char *)MemAlloc(size + sizeof(MemoryBlock) + sizeof(GuardBlock), ptr, fileName, fileLine);
  146. }
  147. if(!mem)
  148. {
  149. ClassThreadUnlock
  150. bool isPullAllocate = (isPoolEnable && size + sizeof(MemoryBlock) + sizeof(GuardBlock) <= MemoryManager_MaxPoolSize);
  151. CoreLogOut("Can't allocate memory! (%s)", isPullAllocate ? "alloc from pull" : "alloc from system memory");
  152. CoreLogOut("from '%s', line %d", fileName, fileLine);
  153. CoreLogOut("Total size = %u, blocks count = %u", totalSize, totalBlocks);
  154. CoreLogOut("Alloc size : %d bytes", size + sizeof(MemoryBlock) + sizeof(GuardBlock));
  155. SysPanicCheckMemory();
  156. #ifdef _XBOX
  157. MEMORYSTATUS memStatus;
  158. GlobalMemoryStatus(&memStatus);
  159. CoreLogOut("Xbox360 available physmemory size : %u bytes", (dword)memStatus.dwAvailPhys);
  160. CoreLogOut("Xbox360 total physmemory size : %u bytes", (dword)memStatus.dwTotalPhys);
  161. CoreLogOut("Xbox360 used physmemory size : %u bytes", (dword)(memStatus.dwTotalPhys - memStatus.dwAvailPhys));
  162. #endif
  163. ClassThreadLock
  164. }
  165. Assert(mem);
  166. if(!ptr)
  167. {
  168. //Регестрируем запись
  169. if(descsCount >= descsMax)
  170. {
  171. descsMax = (descsMax + descsMax/16 + 4096) & ~4095;
  172. descs = (MemoryBlockDesc *)SysAlloc(descsMax*sizeof(MemoryBlockDesc), descs);
  173. }
  174. Assert(descs);
  175. descs[descsCount].blockSize = size;
  176. descs[descsCount].descIndex = GetStringDescIndex(fileName, fileLine);
  177. //Заполняем структуры выделенного блока
  178. ((MemoryBlock *)mem)->descIndex = descsCount;
  179. ((MemoryBlock *)mem)->openGuardBlock = openBlock;
  180. descsCount++;
  181. }
  182. *(GuardBlock *)(mem + sizeof(MemoryBlock) + size) = closeBlock;
  183. descs[((MemoryBlock *)mem)->descIndex].block = (MemoryBlock *)mem;
  184. descs[((MemoryBlock *)mem)->descIndex].blockSize = size;
  185. long descIndex = descs[((MemoryBlock *)mem)->descIndex].descIndex;
  186. DescString * ds = (DescString *)(strings + descIndex);
  187. ds->numAllocBlocks++;
  188. mem += sizeof(MemoryBlock);
  189. #ifdef MM_FILL_MEMORY
  190. if(!ptr)
  191. {
  192. memset(mem, MM_MEMORY_FILLER, size);
  193. }else{
  194. if(size > currentBlockSize)
  195. {
  196. memset(mem + currentBlockSize, MM_MEMORY_FILLER, size - currentBlockSize);
  197. }
  198. }
  199. #endif
  200. ClassThreadUnlock
  201. return mem;
  202. #else
  203. SingleClassThread
  204. //Для дежурной отладки сохраняем место выделения памяти
  205. lastFileName = fileName;
  206. lastFileLine = fileLine;
  207. //Выделяем память
  208. if(isPoolEnable && size <= MemoryManager_MaxPoolSize && size)
  209. {
  210. return PoolAlloc(size, ptr, fileName, fileLine);
  211. }
  212. return MemAlloc(size, ptr, fileName, fileLine);
  213. #endif
  214. }
  215. //Освободить память
  216. void MemoryManager::Free(void * ptr, const char * fileName, long fileLine)
  217. {
  218. SingleClassThread
  219. if(!ptr) return;
  220. deletesPerFrame++;
  221. totalBlocks--;
  222. #ifndef MM_NO_DEBUGMEMORY
  223. if(isPanicCheck) SysPanicCheckMemory();
  224. //Проверяем валидность
  225. MemoryBlock * block = (MemoryBlock *)ptr - 1;
  226. CheckBlock(block);
  227. //Удаляем регистрационную запись
  228. Assert(descs[descsCount - 1].block->descIndex == descsCount - 1);
  229. descs[descsCount - 1].block->descIndex = block->descIndex;
  230. descs[block->descIndex] = descs[descsCount - 1];
  231. descsCount--;
  232. ptr = block;
  233. #endif
  234. FreeInternal(ptr);
  235. }
  236. //Вывести в лог статистику
  237. void MemoryManager::TraceStatistic(CoreCommand_MemStat & stats)
  238. {
  239. SingleClassThread
  240. CoreLogOut("\n\n%s\nMemory statistic:\n%s", line, line);
  241. #ifndef MM_NO_DEBUGMEMORY
  242. if(stats.sortType != cmemstat_onlytotal)
  243. {
  244. if(isPanicCheck) PanicCheckMemory();
  245. //Собираем статистику по файлам
  246. StatData * dataPtr = (StatData *)SysAlloc( (descsCount + 1)*sizeof(StatData), null);
  247. long dataCount = 0;
  248. for(long i = 0; i < sizeof(entry)/sizeof(entry[0]); i++)
  249. {
  250. for(long idx = entry[i]; idx >= 0; )
  251. {
  252. DescString * ds = (DescString *)(strings + idx);
  253. ds->isUse = false;
  254. idx = ds->next;
  255. }
  256. }
  257. for(long i = 0; i < descsCount; i++)
  258. {
  259. //Проверим ограничение по размеру
  260. if(stats.minSize >= 0)
  261. {
  262. if(descs[i].blockSize < dword(stats.minSize)) continue;
  263. }
  264. if(stats.maxSize >= 0)
  265. {
  266. if(descs[i].blockSize > dword(stats.maxSize)) continue;
  267. }
  268. //Имя файла
  269. #ifndef _XBOX
  270. if(descs[i].descIndex < 0)
  271. {
  272. _asm int 3;
  273. }
  274. #endif
  275. long descIndex = descs[i].descIndex;
  276. DescString * ds = (DescString *)(strings + descIndex);
  277. //Посмотрим на имя файла
  278. if(stats.fileName)
  279. {
  280. if(!string::EqualPostfix(ds->fileName, stats.fileName)) continue;
  281. }
  282. //Определим блок в массив
  283. for(long j = 0; j < dataCount; j++)
  284. {
  285. if(dataPtr[j].descIndex == descIndex) break;
  286. DescString * dsj = (DescString *)(strings + dataPtr[j].descIndex);
  287. if(ds->fileLine == dsj->fileLine)
  288. {
  289. if(string::IsEqual(ds->fileName, dsj->fileName))
  290. {
  291. break;
  292. }
  293. }
  294. }
  295. if(j >= dataCount)
  296. {
  297. StatData & sd = dataPtr[dataCount++];
  298. #ifndef _XBOX
  299. if(dataCount > descsCount)
  300. {
  301. _asm int 3;
  302. }
  303. #endif
  304. sd.descIndex = descIndex;
  305. sd.blocksCount = 0;
  306. sd.totalSize = 0;
  307. sd.totalAllocs = 0;
  308. }
  309. StatData & sd = dataPtr[j];
  310. sd.blocksCount++;
  311. sd.totalSize += descs[i].blockSize;
  312. if(!ds->isUse)
  313. {
  314. sd.totalAllocs += ds->numAllocBlocks;
  315. ds->isUse = true;
  316. }
  317. }
  318. //Сортируем в требуемом порядке
  319. long outputLines = dataCount;
  320. const char * sortName = "No sorted";
  321. switch(stats.sortType)
  322. {
  323. case cmemstat_bysize20:
  324. outputLines = coremin(outputLines, 20);
  325. case cmemstat_bysize:
  326. sortName = "Sort by size";
  327. array<StatData>::QSort(TraceStat_SortBySize, dataPtr, dataCount);
  328. break;
  329. case cmemstat_byblocks20:
  330. outputLines = coremin(outputLines, 20);
  331. case cmemstat_byblocks:
  332. sortName = "Sort by blocks";
  333. array<StatData>::QSort(TraceStat_SortByBlocks, dataPtr, dataCount);
  334. break;
  335. case cmemstat_byfreq20:
  336. outputLines = coremin(outputLines, 20);
  337. case cmemstat_byfreq:
  338. sortName = "Sort by count of alloc";
  339. array<StatData>::QSort(TraceStat_SortByFreq, dataPtr, dataCount);
  340. break;
  341. case cmemstat_byfile:
  342. sortName = "Sort by file";
  343. array<StatData>::QSort(TraceStat_SortByFiles, dataPtr, dataCount);
  344. break;
  345. }
  346. CoreLogOut("%s\n%s\n", sortName, line, line);
  347. //Выводим полученную информацию в лог
  348. for(long i = 0; i < outputLines; i++)
  349. {
  350. DescString * ds = (DescString *)(strings + dataPtr[i].descIndex);
  351. CoreLogOut(" size: %8u, blocks: %8u, allocs: %8u, file: %s, line: %i",
  352. dataPtr[i].totalSize,
  353. dataPtr[i].blocksCount,
  354. dataPtr[i].totalAllocs,
  355. ds->fileName,
  356. ds->fileLine);
  357. }
  358. }
  359. #endif
  360. CoreLogOut("\nTotal use memory: %.2f Mb (%u bytes)", totalSize/1024.0/1024.0, totalSize);
  361. #ifdef _XBOX
  362. MEMORYSTATUS memStatus;
  363. GlobalMemoryStatus(&memStatus);
  364. dword use360 = memStatus.dwTotalPhys - memStatus.dwAvailPhys;
  365. CoreLogOut("Total xbox360 use memory: %.2f Mb (%u bytes)", use360/1024.0/1024.0, use360);
  366. #endif
  367. CoreLogOut("Peak allocate memory size: %.2f Mb (%u bytes)", maxSize/1024.0/1024.0, maxSize);
  368. #ifdef _XBOX
  369. CoreLogOut("Pick memory usages on xbox360: %.2f Mb (%u bytes)", maxUsed360/1024.0/1024.0, maxUsed360);
  370. #endif
  371. CoreLogOut("Total use blocks: %u", totalBlocks);
  372. CoreLogOut("Total use blocks in pools: %u", poolBlocks);
  373. CoreLogOut("%s\n\n", line);
  374. }
  375. bool MemoryManager::TraceStat_SortBySize(const StatData & d1, const StatData & d2)
  376. {
  377. return d1.totalSize > d2.totalSize;
  378. }
  379. bool MemoryManager::TraceStat_SortByBlocks(const StatData & d1, const StatData & d2)
  380. {
  381. return d1.blocksCount > d2.blocksCount;
  382. }
  383. bool MemoryManager::TraceStat_SortByFreq(const StatData & d1, const StatData & d2)
  384. {
  385. return d1.totalAllocs > d2.totalAllocs;
  386. }
  387. bool MemoryManager::TraceStat_SortByFiles(const StatData & d1, const StatData & d2)
  388. {
  389. #ifndef MM_NO_DEBUGMEMORY
  390. DescString * ds1 = (DescString *)(memoryManager.strings + d1.descIndex);
  391. DescString * ds2 = (DescString *)(memoryManager.strings + d2.descIndex);
  392. long res = strcmp(ds1->fileName, ds2->fileName);
  393. if(res == 0)
  394. {
  395. return ds1->fileLine < ds2->fileLine;
  396. }
  397. return res < 0;
  398. #else
  399. return false;
  400. #endif
  401. }
  402. //Вернуть статистику
  403. void MemoryManager::GetStatistic(CoreCommand_GetMemStat & stats)
  404. {
  405. if(!stats.fileName || stats.fileName[0] == 0)
  406. {
  407. stats.totalAllocSize = totalSize;
  408. stats.numBlocks = totalBlocks;
  409. stats.allocsPerFrame = allocsPerFrame;
  410. stats.deletesPerFrame = deletesPerFrame;
  411. return;
  412. }
  413. #ifndef MM_NO_DEBUGMEMORY
  414. SingleClassThread
  415. stats.totalAllocSize = 0;
  416. stats.numBlocks = 0;
  417. stats.allocsCount = 0;
  418. for(long i = 0; i < sizeof(entry)/sizeof(entry[0]); i++)
  419. {
  420. for(long idx = entry[i]; idx >= 0; )
  421. {
  422. DescString * ds = (DescString *)(strings + idx);
  423. ds->isUse = false;
  424. idx = ds->next;
  425. }
  426. }
  427. for(long i = 0; i < descsCount; i++)
  428. {
  429. //Имя файла
  430. Assert(descs[i].descIndex >= 0);
  431. long descIndex = descs[i].descIndex;
  432. DescString * ds = (DescString *)(strings + descIndex);
  433. //Посмотрим на имя файла
  434. if(stats.fileLine > 0 && ds->fileLine != stats.fileLine) continue;
  435. if(!string::EqualPostfix(ds->fileName, stats.fileName)) continue;
  436. stats.totalAllocSize += descs[i].blockSize;
  437. stats.numBlocks++;
  438. if(!ds->isUse)
  439. {
  440. stats.allocsCount += ds->numAllocBlocks;
  441. ds->isUse = true;
  442. }
  443. }
  444. #else
  445. stats.totalAllocSize = 0;
  446. stats.numBlocks = 0;
  447. stats.allocsPerFrame = 0;
  448. stats.deletesPerFrame = 0;
  449. #endif
  450. }
  451. //Посчитать память занимаемую отладочной информацией менеджера
  452. void MemoryManager::GetManagerStat(CoreCommand_GetMemManagerStat & stats)
  453. {
  454. #ifndef MM_NO_DEBUGMEMORY
  455. stats.allocsForBlockDesc = descsMax*sizeof(MemoryBlockDesc);
  456. stats.allocsForGuards = totalBlocks*(sizeof(MemoryBlock) + sizeof(GuardBlock));
  457. stats.allocsForNameBase = stringsMax;
  458. stats.totalSizeUseForDebug = stats.allocsForBlockDesc + stats.allocsForGuards + stats.allocsForNameBase;
  459. #endif
  460. }
  461. //Режим панической проверки
  462. void MemoryManager::SetPanicCheckMemoryMode(bool isSet)
  463. {
  464. #ifndef MM_NO_DEBUGMEMORY
  465. isPanicCheck = isSet;
  466. if(isSet)
  467. {
  468. isPanicCheckEnable = true;
  469. }
  470. #endif
  471. }
  472. //Запустить - остоновить усиленную проверку памяти
  473. void MemoryManager::EnablePanicCheckMemory(bool isEnable)
  474. {
  475. #ifndef MM_NO_DEBUGMEMORY
  476. isPanicCheckEnable = isEnable;
  477. #endif
  478. }
  479. //Стоит ли режим панической проверки
  480. bool MemoryManager::IsPanicCheckMemoryMode()
  481. {
  482. #ifndef MM_NO_DEBUGMEMORY
  483. return isPanicCheck;
  484. #else
  485. return false;
  486. #endif
  487. }
  488. //Включить пулы памяти
  489. void MemoryManager::EnableMemPools()
  490. {
  491. isPoolEnable = true;
  492. }
  493. //Включены ли пулы памяти
  494. bool MemoryManager::IsEnableMemPools()
  495. {
  496. return isPoolEnable;
  497. }
  498. //Обновить состояние мэнеджера
  499. void MemoryManager::Update()
  500. {
  501. allocsPerFrame = 0;
  502. deletesPerFrame = 0;
  503. }
  504. //Проверить на целостность всю выделенную память
  505. void MemoryManager::PanicCheckMemory()
  506. {
  507. #ifndef MM_NO_DEBUGMEMORY
  508. SingleClassThread
  509. bool cur = isPanicCheckEnable;
  510. isPanicCheckEnable = true;
  511. SysPanicCheckMemory();
  512. isPanicCheckEnable = cur;
  513. #endif
  514. }
  515. //Сделать плановую проверку
  516. void MemoryManager::CheckMemoryStep()
  517. {
  518. #ifndef MM_NO_DEBUGMEMORY
  519. SingleClassThread
  520. Assert(this == &memoryManager);
  521. Assert(emptyMemory == MemoryManager_CheckDword);
  522. for(long i = 0; i < ARRSIZE(guardIn); i++)
  523. {
  524. Assert(guardIn[i] == MemoryManager_CheckDword + i);
  525. }
  526. for(long i = 0; i < ARRSIZE(guardOut); i++)
  527. {
  528. Assert(guardOut[i] == MemoryManager_CheckDword - i);
  529. }
  530. if(descsCount <= 0) return;
  531. long count = descsCount/20;
  532. if(count < 1) count = 1;
  533. for(long i = 0; i < count; i++)
  534. {
  535. if(currentCheck < 0 || currentCheck >= descsCount)
  536. {
  537. currentCheck = 0;
  538. }
  539. CheckBlock(descs[currentCheck].block);
  540. currentCheck++;
  541. }
  542. #endif
  543. }
  544. //-------------------------------------------------------------------------------------------------------
  545. //Внутреннии незащищёные критическими секциями функции
  546. //-------------------------------------------------------------------------------------------------------
  547. //Проверить на целостность всю выделенную память
  548. void MemoryManager::SysPanicCheckMemory()
  549. {
  550. #ifndef MM_NO_DEBUGMEMORY
  551. if(!isPanicCheckEnable) return;
  552. Assert(this == &memoryManager);
  553. Assert(emptyMemory == MemoryManager_CheckDword);
  554. for(long i = 0; i < ARRSIZE(guardIn); i++)
  555. {
  556. Assert(guardIn[i] == MemoryManager_CheckDword + i);
  557. }
  558. for(long i = 0; i < ARRSIZE(guardOut); i++)
  559. {
  560. Assert(guardOut[i] == MemoryManager_CheckDword - i);
  561. }
  562. for(long i = 0; i < descsCount; i++)
  563. {
  564. CheckBlock(descs[i].block);
  565. }
  566. Assert(_heapchk() == _HEAPOK);
  567. #endif
  568. }
  569. //-------------------------------------------------------------------------------------------------------
  570. //Работа с памятью менеджера
  571. //-------------------------------------------------------------------------------------------------------
  572. //Выделить память в пуле
  573. __forceinline void * MemoryManager::PoolAlloc(dword size, void * ptr, const char * fileName, long fileLine)
  574. {
  575. byte * mem = (byte *)pools.Alloc(size);
  576. if(ptr)
  577. {
  578. //Ищем получаем размер блока
  579. dword s = pools.Size(ptr);
  580. if(!s) s = SysSize(ptr);
  581. if(s > size) s = size;
  582. for(byte * dst = mem, * src = (byte *)ptr; s; s--)
  583. {
  584. *dst++ = *src++;
  585. }
  586. FreeInternal(ptr);
  587. }
  588. poolBlocks++;
  589. if(maxPoolBlocks < poolBlocks) maxPoolBlocks = poolBlocks;
  590. return mem;
  591. }
  592. //Освободить память в пуле
  593. __forceinline bool MemoryManager::PoolFree(void * ptr)
  594. {
  595. if(pools.Free(ptr))
  596. {
  597. poolBlocks--;
  598. return true;
  599. }
  600. return false;
  601. }
  602. //Выделить память вне пула
  603. __forceinline void * MemoryManager::MemAlloc(dword size, void * ptr, const char * fileName, long fileLine)
  604. {
  605. if(ptr)
  606. {
  607. dword s = pools.Size(ptr);
  608. if(s)
  609. {
  610. //Перевыделение из пула
  611. byte * mem = (byte *)SysAlloc(size, null);
  612. if(s > size) s = size;
  613. for(byte * dst = mem, * src = (byte *)ptr; s; s--)
  614. {
  615. *dst++ = *src++;
  616. }
  617. FreeInternal(ptr);
  618. return mem;
  619. }
  620. }
  621. return SysAlloc(size, ptr);
  622. }
  623. //Освободить память
  624. __forceinline void MemoryManager::FreeInternal(void * ptr)
  625. {
  626. if(isPoolEnable)
  627. {
  628. if(PoolFree(ptr))
  629. {
  630. return;
  631. }
  632. }
  633. SysFree(ptr);
  634. }
  635. //Проверить блок памяти
  636. void _fastcall MemoryManager::CheckBlock(MemoryBlock * block)
  637. {
  638. #ifndef MM_NO_DEBUGMEMORY
  639. if(!(block->openGuardBlock == openBlock))
  640. {
  641. if(IsValidateBlockPointer(block))
  642. {
  643. TraceDamagedBlocks();
  644. Assert(block->openGuardBlock == openBlock);
  645. }else{
  646. CoreLogOut("MemoryManager: Memory is damage (open guard block) 0x%.8x", block);
  647. Assert(false);
  648. }
  649. }
  650. if(!(block->descIndex >= 0 && block->descIndex < descsCount))
  651. {
  652. if(IsValidateBlockPointer(block))
  653. {
  654. TraceDamagedBlocks();
  655. Assert(block->descIndex >= 0 && block->descIndex < descsCount);
  656. }else{
  657. CoreLogOut("MemoryManager: Memory is damage (close guard block) 0x%.8x", block);
  658. Assert(false);
  659. }
  660. }
  661. if(!(descs[block->descIndex].block == block))
  662. {
  663. if(IsValidateBlockPointer(block))
  664. {
  665. TraceDamagedBlocks();
  666. Assert(descs[block->descIndex].block == block);
  667. }else{
  668. CoreLogOut("MemoryManager: Invalidate pointer 0x%.8x", block);
  669. Assert(false);
  670. }
  671. }
  672. if(!(*(GuardBlock *)((byte *)(block + 1) + descs[block->descIndex].blockSize) == closeBlock))
  673. {
  674. TraceDamagedBlocks();
  675. Assert(*(GuardBlock *)((byte *)(block + 1) + descs[block->descIndex].blockSize) == closeBlock);
  676. }
  677. #endif
  678. }
  679. //Проверить на валидность поинтер
  680. bool MemoryManager::IsValidateBlockPointer(MemoryBlock * block)
  681. {
  682. #ifndef MM_NO_DEBUGMEMORY
  683. for(long i = 0; i < descsCount; i++)
  684. {
  685. if(descs[i].block == block) return true;
  686. }
  687. return false;
  688. #else
  689. return true;
  690. #endif
  691. }
  692. //Проверить все блоки и вывести всю доступнукю информацию по разрушеным блокам
  693. void MemoryManager::TraceDamagedBlocks()
  694. {
  695. #ifndef MM_NO_DEBUGMEMORY
  696. for(long i = 0; i < descsCount; i++)
  697. {
  698. MemoryBlock * block = descs[i].block;
  699. bool isDamaged = false;
  700. bool dmgOpenBlock = false;
  701. bool dmgCloseBlock = false;
  702. bool dmgIndex = false;
  703. if(!(block->openGuardBlock == openBlock))
  704. {
  705. isDamaged = true;
  706. dmgOpenBlock = true;
  707. }
  708. if(!(*(GuardBlock *)((byte *)(block + 1) + descs[i].blockSize) == closeBlock))
  709. {
  710. isDamaged = true;
  711. dmgCloseBlock = true;
  712. }
  713. if(block->descIndex != i)
  714. {
  715. isDamaged = true;
  716. dmgIndex = true;
  717. }
  718. if(!isDamaged) continue;
  719. CoreLogOut("%s\nMemory block is damaged", line);
  720. CoreLogOut(" addr: 0x%.8x", block);
  721. CoreLogOut(" size: %d", descs[i].blockSize);
  722. if(descs[i].descIndex >= 0)
  723. {
  724. DescString * ds = (DescString *)(strings + descs[i].descIndex);
  725. CoreLogOut(" alloc file name: %s", ds->fileName);
  726. CoreLogOut(" alloc file line: %i", ds->fileLine);
  727. CoreLogOut(" alloc blocks: %i", ds->numAllocBlocks);
  728. }
  729. if(dmgIndex)
  730. {
  731. CoreLogOut(" * Block desc index damaged");
  732. }
  733. if(dmgOpenBlock)
  734. {
  735. CoreLogOut(" * Open guard block damaged");
  736. }
  737. if(dmgCloseBlock)
  738. {
  739. CoreLogOut(" * Close guard block damaged");
  740. }
  741. CoreLogOut(" Previous block info");
  742. if(i > 0)
  743. {
  744. const char * file = "Unknown";
  745. long line = 0;
  746. if(descs[i - 1].descIndex >= 0)
  747. {
  748. DescString * ds = (DescString *)(strings + descs[i - 1].descIndex);
  749. file = ds->fileName;
  750. line = ds->fileLine;
  751. }
  752. CoreLogOut(" alloc file name: %s", file);
  753. CoreLogOut(" alloc file line: %i", line);
  754. }else{
  755. CoreLogOut(" no previous blocks");
  756. }
  757. CoreLogOut(" Next block info");
  758. if(i + 1 < descsCount)
  759. {
  760. const char * file = "Unknown";
  761. long line = 0;
  762. if(descs[i + 1].descIndex >= 0)
  763. {
  764. DescString * ds = (DescString *)(strings + descs[i + 1].descIndex);
  765. file = ds->fileName;
  766. line = ds->fileLine;
  767. }
  768. CoreLogOut(" alloc file name: %s", file);
  769. CoreLogOut(" alloc file line: %i", line);
  770. }else{
  771. CoreLogOut(" no next blocks");
  772. }
  773. }
  774. #endif
  775. }
  776. //Получить индекс строки
  777. __forceinline long MemoryManager::GetStringDescIndex(const char * fileName, long fileLine)
  778. {
  779. #ifndef MM_NO_DEBUGMEMORY
  780. static const char * emptyString = "";
  781. if(!fileName) fileName = emptyString;
  782. if(fileLine <= 0) fileLine = 0;
  783. //Ищим среди добавленных
  784. union GetDword
  785. {
  786. const char * str;
  787. struct
  788. {
  789. word lo;
  790. word hi;
  791. };
  792. } getDword;
  793. getDword.str = fileName;
  794. long eidx = (getDword.lo ^ getDword.hi ^ fileLine) & (ARRSIZE(entry) - 1);
  795. for(long i = entry[eidx]; i >= 0; )
  796. {
  797. DescString * desc = (DescString *)(strings + i);
  798. if(desc->fileNamePtr == fileName && desc->fileLine == fileLine)
  799. {
  800. return i;
  801. }
  802. i = desc->next;
  803. }
  804. //Добавляем
  805. long len = (long)strlen(fileName);
  806. if(stringsSize + len + sizeof(DescString) >= stringsMax)
  807. {
  808. stringsMax = (stringsMax + len + sizeof(DescString) + 4095) & ~4095;
  809. strings = (char *)SysAlloc(stringsMax, strings);
  810. }
  811. DescString & ds = (DescString &)*(strings + stringsSize);
  812. i = entry[eidx];
  813. if(i >= 0)
  814. {
  815. //Добавляемся в конец списка (для более качественной работы кэша)
  816. while(true)
  817. {
  818. DescString * desc = (DescString *)(strings + i);
  819. if(desc->next < 0) break;
  820. i = desc->next;
  821. }
  822. ((DescString *)(strings + i))->next = stringsSize;
  823. }else{
  824. entry[eidx] = stringsSize;
  825. }
  826. ds.next = -1;
  827. ds.numAllocBlocks = 0;
  828. ds.fileNamePtr = fileName;
  829. ds.fileLine = fileLine;
  830. for(long i = 0; i <= len; i++) ds.fileName[i] = fileName[i];
  831. i = stringsSize;
  832. stringsSize += len + sizeof(DescString);
  833. return i;
  834. #else
  835. return -1;
  836. #endif
  837. }
  838. //-------------------------------------------------------------------------------------------------------
  839. //Работа с системной памятью
  840. //-------------------------------------------------------------------------------------------------------
  841. //Выделить системную память
  842. __forceinline void * MemoryManager::SysAlloc(dword size, void * ptr)
  843. {
  844. //Обрабатываем блок 0-ого размера
  845. if(ptr == &emptyMemory)
  846. {
  847. ptr = null;
  848. }
  849. if(!size)
  850. {
  851. SysFree(ptr);
  852. return &emptyMemory;
  853. }
  854. //Перевыделяем (выделяем) память
  855. if(ptr)
  856. {
  857. totalSize -= SysSize(ptr);
  858. }
  859. totalSize += size;
  860. if(maxSize < totalSize) maxSize = totalSize;
  861. ptr = realloc(ptr, size);
  862. #ifndef MM_NO_DEBUGMEMORY
  863. MEMORYSTATUS memStatus;
  864. GlobalMemoryStatus(&memStatus);
  865. dword s = dword(memStatus.dwTotalPhys - memStatus.dwAvailPhys);
  866. if(s > maxUsed360) maxUsed360 = s;
  867. #endif
  868. return ptr;
  869. }
  870. //Освободить системную память
  871. __forceinline void MemoryManager::SysFree(void * ptr)
  872. {
  873. if(!ptr) return;
  874. if(ptr == &emptyMemory)
  875. {
  876. return;
  877. }
  878. totalSize -= SysSize(ptr);
  879. free(ptr);
  880. }
  881. //Получить размер системного блока
  882. __forceinline dword MemoryManager::SysSize(void * ptr)
  883. {
  884. if(!ptr) return 0;
  885. if(ptr == &emptyMemory) return 0;
  886. return (dword)_msize(ptr);
  887. }
  888. //-----------------------------------------------------------------------------------------------------------------
  889. //MemoryPool
  890. //-----------------------------------------------------------------------------------------------------------------
  891. template<int Size> MemoryManager::MemoryPool<Size>::MemoryPool()
  892. {
  893. minAddr = null;
  894. maxAddr = null;
  895. blocks = null;
  896. blocksCount = 0;
  897. blocksMax = 0;
  898. }
  899. template<int Size> MemoryManager::MemoryPool<Size>::~MemoryPool()
  900. {
  901. if(blocks)
  902. {
  903. for(dword i = 0; i < blocksCount; i++)
  904. {
  905. MemoryManager::SysFree(blocks[i]);
  906. }
  907. MemoryManager::SysFree(blocks);
  908. }
  909. minAddr = null;
  910. maxAddr = null;
  911. blocks = null;
  912. blocksCount = 0;
  913. blocksMax = 0;
  914. }
  915. //Выделить память данного размера
  916. template<int Size> void * MemoryManager::MemoryPool<Size>::Alloc()
  917. {
  918. //Ищем кусок среди выделеных блоков
  919. for(dword i = 0; i < blocksCount; i++)
  920. {
  921. Block * b = blocks[i];
  922. for(long j = 0; j < (4096/Size + 31)/32; j++)
  923. {
  924. if(b->use[j] != 0xffffffff)
  925. {
  926. //Здесь есть свободный кусок, выделим его
  927. for(dword bit = 1, index = 0; b->use[j] & bit; bit <<= 1, index++);
  928. Assert(index < 32);
  929. b->use[j] |= bit;
  930. return AddAddress(b->pool[j*32 + index]);
  931. }
  932. }
  933. }
  934. //Ненашлось свободного куска, надо выделить новый блок
  935. if(blocksCount >= blocksMax)
  936. {
  937. blocksMax += 64;
  938. blocks = (Block **)MemoryManager::SysAlloc(blocksMax*sizeof(Block *), blocks);
  939. }
  940. Block * b = blocks[blocksCount++] = (Block *)MemoryManager::SysAlloc(sizeof(Block), null);
  941. for(long i = 0; i < ARRSIZE(b->use); i++)
  942. {
  943. b->use[i] = 0xffffffff;
  944. }
  945. for(long i = 0; i < 4096/Size/32; i++)
  946. {
  947. b->use[i] = 0;
  948. }
  949. for(i *= 32; i < 4096/Size; i++)
  950. {
  951. dword bit = 1 << (i & 31);
  952. b->use[i/32] &= ~bit;
  953. }
  954. //Выделим новый кусок в новом блоке
  955. b->use[0] |= 1;
  956. return AddAddress(b->pool[0]);
  957. }
  958. //Попытаться освободить память
  959. template<int Size> bool MemoryManager::MemoryPool<Size>::Free(void * ptr)
  960. {
  961. //Проверим глобально
  962. if(ptr < minAddr) return false;
  963. if(ptr > maxAddr) return false;
  964. //Проверим каждый блок в отдельности
  965. for(dword i = 0; i < blocksCount; i++)
  966. {
  967. if(ptr < blocks[i]->pool[0]) continue;
  968. if(ptr >= (byte *)blocks[i]->pool[0] + sizeof(blocks[i]->pool)) continue;
  969. break;
  970. }
  971. if(i >= blocksCount) return false;
  972. //Это тут, отметим удаление
  973. Block * b = blocks[i];
  974. Assert(((byte *)ptr - (byte *)b->pool)%Size == 0);
  975. long index = dword((byte *)ptr - (byte *)b->pool)/Size;
  976. dword bit = 1 << (index & 31);
  977. b->use[index/32] &= ~bit;
  978. return true;
  979. }
  980. //Добавить адрес в общий диапазон
  981. template<int Size> __forceinline void * MemoryManager::MemoryPool<Size>::AddAddress(void * ptr)
  982. {
  983. if(!minAddr || minAddr > ptr)
  984. {
  985. minAddr = ptr;
  986. }
  987. if(!maxAddr || maxAddr < ptr)
  988. {
  989. maxAddr = ptr;
  990. }
  991. return ptr;
  992. }
  993. //Получить размер блока по адресу
  994. template<int Size> dword MemoryManager::MemoryPool<Size>::GetSize(void * ptr)
  995. {
  996. //Проверим глобально
  997. if(ptr < minAddr) return false;
  998. if(ptr > maxAddr) return false;
  999. //Проверим каждый блок в отдельности
  1000. for(dword i = 0; i < blocksCount; i++)
  1001. {
  1002. if(ptr < blocks[i]) continue;
  1003. if(ptr >= (byte *)blocks[i]->pool[0] + sizeof(blocks[i]->pool)) continue;
  1004. return Size;
  1005. }
  1006. return 0;
  1007. }
  1008. //-----------------------------------------------------------------------------------------------------------------
  1009. //MemoryPools
  1010. //-----------------------------------------------------------------------------------------------------------------
  1011. MemoryManager::MemoryPools::MemoryPools()
  1012. {
  1013. pools[0] = &pool4; pools[1] = &pool8; pools[2] = &pool12; pools[3] = &pool16;
  1014. pools[4] = &pool20; pools[5] = &pool24; pools[6] = &pool28; pools[7] = &pool32;
  1015. pools[8] = &pool36; pools[9] = &pool40; pools[10] = &pool44; pools[11] = &pool48;
  1016. pools[12] = &pool52; pools[13] = &pool56; pools[14] = &pool60; pools[15] = &pool64;
  1017. pools[16] = &pool68; pools[17] = &pool72; pools[18] = &pool76; pools[19] = &pool80;
  1018. pools[20] = &pool84; pools[21] = &pool88; pools[22] = &pool92; pools[23] = &pool96;
  1019. minAddr = null;
  1020. maxAddr = null;
  1021. }
  1022. __forceinline void * MemoryManager::MemoryPools::Alloc(dword size)
  1023. {
  1024. Assert(size);
  1025. dword index = (size - 1)/4;
  1026. Assert(index < 24);
  1027. void * mem = pools[index]->Alloc();
  1028. Assert(mem);
  1029. if(!minAddr || minAddr > mem)
  1030. {
  1031. minAddr = mem;
  1032. }
  1033. if(!maxAddr || maxAddr < mem)
  1034. {
  1035. maxAddr = mem;
  1036. }
  1037. return mem;
  1038. }
  1039. __forceinline bool MemoryManager::MemoryPools::Free(void * ptr)
  1040. {
  1041. if(ptr > maxAddr) return false;
  1042. if(ptr < minAddr) return false;
  1043. for(long i = 0; i < 24; i++)
  1044. {
  1045. if(pools[i]->Free(ptr)) return true;
  1046. }
  1047. return false;
  1048. }
  1049. __forceinline dword MemoryManager::MemoryPools::Size(void * ptr)
  1050. {
  1051. if(ptr > maxAddr) return 0;
  1052. if(ptr < minAddr) return 0;
  1053. dword s = 0;
  1054. for(long i = 0; i < 24; i++)
  1055. {
  1056. if(s = pools[i]->GetSize(ptr)) return s;
  1057. }
  1058. return 0;
  1059. }