memtrack.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. #ifdef XIOS_MEMTRACK
  2. /*
  3. Copyright (c) 2002, 2008 Curtis Bartley
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions
  7. are met:
  8. - Redistributions of source code must retain the above copyright
  9. notice, this list of conditions and the following disclaimer.
  10. - Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions and the following disclaimer in the
  12. documentation and/or other materials provided with the
  13. distribution.
  14. - Neither the name of Curtis Bartley nor the names of any other
  15. contributors may be used to endorse or promote products derived
  16. from this software without specific prior written permission.
  17. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  26. STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  28. OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /* ---------------------------------------- includes */
  31. #include <assert.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <algorithm>
  35. #include <cstring>
  36. #include <new>
  37. #include <iostream>
  38. #include <sstream>
  39. #include <string>
  40. #include <execinfo.h>
  41. #include "memtrack.hpp"
  42. #undef new // IMPORTANT!
  43. extern "C"
  44. {
  45. void addr2line(const char *file_name, char** addr, int naddr) ;
  46. #ifdef XIOS_MEMTRACK_LIGHT
  47. void addr2line(const char *file_name, char** addr, int naddr) {}
  48. #endif
  49. }
  50. /* ------------------------------------------------------------ */
  51. /* -------------------- namespace MemTrack -------------------- */
  52. /* ------------------------------------------------------------ */
  53. namespace MemTrack
  54. {
  55. size_t currentMemorySize=0 ;
  56. size_t maxMemorySize=0 ;
  57. size_t getCurrentMemorySize(void) {return currentMemorySize; }
  58. size_t getMaxMemorySize(void) {return maxMemorySize ; }
  59. /* ------------------------------------------------------------ */
  60. /* --------------------- class BlockHeader -------------------- */
  61. /* ------------------------------------------------------------ */
  62. class BlockHeader
  63. {
  64. private: // static member variables
  65. static BlockHeader *ourFirstNode;
  66. private: // member variables
  67. BlockHeader *myPrevNode;
  68. BlockHeader *myNextNode;
  69. size_t myRequestedSize;
  70. char const *myFilename;
  71. int myLineNum;
  72. char const *myTypeName;
  73. size_t stackSize ;
  74. void* stackArray[20] ;
  75. public: // members
  76. BlockHeader(size_t requestedSize);
  77. ~BlockHeader();
  78. size_t GetRequestedSize() const { return myRequestedSize; }
  79. char const *GetFilename() const { return myFilename; }
  80. int GetLineNum() const { return myLineNum; }
  81. char const *GetTypeName() const { return myTypeName; }
  82. void Stamp(char const *filename, int lineNum, char const *typeName);
  83. void backTrace(void) ;
  84. static void AddNode(BlockHeader *node);
  85. static void RemoveNode(BlockHeader *node);
  86. static size_t CountBlocks();
  87. static void GetBlocks(BlockHeader **blockHeaderPP);
  88. static bool TypeGreaterThan(BlockHeader *header1, BlockHeader *header2);
  89. };
  90. /* ---------------------------------------- BlockHeader static member variables */
  91. BlockHeader *BlockHeader::ourFirstNode = NULL;
  92. /* ---------------------------------------- BlockHeader constructor */
  93. BlockHeader::BlockHeader(size_t requestedSize)
  94. {
  95. myPrevNode = NULL;
  96. myNextNode = NULL;
  97. myRequestedSize = requestedSize;
  98. myFilename = "[unknown]";
  99. myLineNum = 0;
  100. myTypeName = "[unknown]";
  101. stackSize=backtrace(stackArray,20) ;
  102. }
  103. /* ---------------------------------------- BlockHeader destructor */
  104. BlockHeader::~BlockHeader()
  105. {
  106. }
  107. /* ---------------------------------------- BlockHeader Stamp */
  108. void BlockHeader::Stamp(char const *filename, int lineNum, char const *typeName)
  109. {
  110. myFilename = filename;
  111. myLineNum = lineNum;
  112. myTypeName = typeName;
  113. }
  114. void BlockHeader::backTrace(void)
  115. {
  116. // oss<<"addr2line -C -f -i -s -e ../bin/test_client.exe " ;
  117. char *addr ;
  118. char buffer[20] ;
  119. addr=buffer ;
  120. for(int i=0;i<stackSize;i++)
  121. {
  122. std::ostringstream oss ;
  123. oss<<stackArray[i] ;
  124. strcpy(addr,oss.str().c_str()) ;
  125. addr2line("/proc/self/exe",&addr,1) ;
  126. }
  127. }
  128. /* ---------------------------------------- BlockHeader AddNode */
  129. void BlockHeader::AddNode(BlockHeader *node)
  130. {
  131. assert(node != NULL);
  132. assert(node->myPrevNode == NULL);
  133. assert(node->myNextNode == NULL);
  134. // If we have at least one node in the list ...
  135. if (ourFirstNode != NULL)
  136. {
  137. // ... make the new node the first node's predecessor.
  138. assert(ourFirstNode->myPrevNode == NULL);
  139. ourFirstNode->myPrevNode = node;
  140. }
  141. // Make the first node the new node's succesor.
  142. node->myNextNode = ourFirstNode;
  143. // Make the new node the first node.
  144. ourFirstNode = node;
  145. }
  146. /* ---------------------------------------- BlockHeader RemoveNode */
  147. void BlockHeader::RemoveNode(BlockHeader *node)
  148. {
  149. assert(node != NULL);
  150. assert(ourFirstNode != NULL);
  151. // If target node is the first node in the list...
  152. if (ourFirstNode == node)
  153. {
  154. // ... make the target node's successor the first node.
  155. assert(ourFirstNode->myPrevNode == NULL);
  156. ourFirstNode = node->myNextNode;
  157. }
  158. // Link target node's predecessor, if any, to its successor.
  159. if (node->myPrevNode != NULL)
  160. {
  161. node->myPrevNode->myNextNode = node->myNextNode;
  162. }
  163. // Link target node's successor, if any, to its predecessor.
  164. if (node->myNextNode != NULL)
  165. {
  166. node->myNextNode->myPrevNode = node->myPrevNode;
  167. }
  168. // Clear target node's previous and next pointers.
  169. node->myPrevNode = NULL;
  170. node->myNextNode = NULL;
  171. }
  172. /* ---------------------------------------- BlockHeader CountBlocks */
  173. size_t BlockHeader::CountBlocks()
  174. {
  175. size_t count = 0;
  176. BlockHeader *currNode = ourFirstNode;
  177. while (currNode != NULL)
  178. {
  179. count++;
  180. currNode = currNode->myNextNode;
  181. }
  182. return count;
  183. }
  184. /* ---------------------------------------- BlockHeader GetBlocks */
  185. void BlockHeader::GetBlocks(BlockHeader **blockHeaderPP)
  186. {
  187. BlockHeader *currNode = ourFirstNode;
  188. while (currNode != NULL)
  189. {
  190. *blockHeaderPP = currNode;
  191. blockHeaderPP++;
  192. currNode = currNode->myNextNode;
  193. }
  194. }
  195. /* ---------------------------------------- BlockHeader TypeGreaterThan */
  196. bool BlockHeader::TypeGreaterThan(BlockHeader *header1, BlockHeader *header2)
  197. {
  198. return (strcmp(header1->myTypeName, header2->myTypeName) > 0);
  199. }
  200. /* ------------------------------------------------------------ */
  201. /* ---------------------- class Signature --------------------- */
  202. /* ------------------------------------------------------------ */
  203. class Signature
  204. {
  205. private: // constants
  206. static const unsigned int SIGNATURE1 = 0xCAFEBABE;
  207. static const unsigned int SIGNATURE2 = 0xFACEFACE;
  208. private: // member variables
  209. unsigned int mySignature1;
  210. unsigned int mySignature2;
  211. public: // construction/destruction
  212. Signature() : mySignature1(SIGNATURE1), mySignature2(SIGNATURE2) {};
  213. ~Signature() { mySignature1 = 0; mySignature2 = 0; }
  214. public: // static member functions
  215. static bool IsValidSignature(const Signature *pProspectiveSignature)
  216. {
  217. try
  218. {
  219. if (pProspectiveSignature->mySignature1 != SIGNATURE1) return false;
  220. if (pProspectiveSignature->mySignature2 != SIGNATURE2) return false;
  221. return true;
  222. }
  223. catch (...)
  224. {
  225. return false;
  226. }
  227. }
  228. };
  229. /* ------------------------------------------------------------ */
  230. /* -------------------- address conversion -------------------- */
  231. /* ------------------------------------------------------------ */
  232. /* We divide the memory blocks we allocate into two "chunks", the
  233. * "prolog chunk" where we store information about the allocation,
  234. * and the "user chunk" which we return to the caller to use.
  235. */
  236. /* ---------------------------------------- alignment */
  237. const size_t ALIGNMENT = 4;
  238. /* If "value" (a memory size or offset) falls on an alignment boundary,
  239. * then just return it. Otherwise return the smallest number larger
  240. * than "value" that falls on an alignment boundary.
  241. */
  242. #define PAD_TO_ALIGNMENT_BOUNDARY(value) \
  243. ((value) + ((ALIGNMENT - ((value) % ALIGNMENT)) % ALIGNMENT))
  244. /* ---------------------------------------- chunk structs */
  245. /* We declare incomplete structures for each chunk, just to
  246. * provide type safety.
  247. */
  248. struct PrologChunk;
  249. struct UserChunk;
  250. /* ---------------------------------------- chunk sizes and offsets */
  251. const size_t SIZE_BlockHeader = PAD_TO_ALIGNMENT_BOUNDARY(sizeof(BlockHeader));
  252. const size_t SIZE_Signature = PAD_TO_ALIGNMENT_BOUNDARY(sizeof(Signature));
  253. const size_t OFFSET_BlockHeader = 0;
  254. const size_t OFFSET_Signature = OFFSET_BlockHeader + SIZE_BlockHeader;
  255. const size_t OFFSET_UserChunk = OFFSET_Signature + SIZE_Signature;
  256. const size_t SIZE_PrologChunk = OFFSET_UserChunk;
  257. /* ---------------------------------------- GetUserAddress */
  258. static UserChunk *GetUserAddress(PrologChunk *pProlog)
  259. {
  260. char *pchProlog = reinterpret_cast<char *>(pProlog);
  261. char *pchUser = pchProlog + OFFSET_UserChunk;
  262. UserChunk *pUser = reinterpret_cast<UserChunk *>(pchUser);
  263. return pUser;
  264. }
  265. /* ---------------------------------------- GetPrologAddress */
  266. static PrologChunk *GetPrologAddress(UserChunk *pUser)
  267. {
  268. char *pchUser = reinterpret_cast<char *>(pUser);
  269. char *pchProlog = pchUser - OFFSET_UserChunk;
  270. PrologChunk *pProlog = reinterpret_cast<PrologChunk *>(pchProlog);
  271. return pProlog;
  272. }
  273. /* ---------------------------------------- GetHeaderAddress */
  274. static BlockHeader *GetHeaderAddress(PrologChunk *pProlog)
  275. {
  276. char *pchProlog = reinterpret_cast<char *>(pProlog);
  277. char *pchHeader = pchProlog + OFFSET_BlockHeader;
  278. BlockHeader *pHeader = reinterpret_cast<BlockHeader *>(pchHeader);
  279. return pHeader;
  280. }
  281. /* ---------------------------------------- GetSignatureAddress */
  282. static Signature *GetSignatureAddress(PrologChunk *pProlog)
  283. {
  284. char *pchProlog = reinterpret_cast<char *>(pProlog);
  285. char *pchSignature = pchProlog + OFFSET_Signature;
  286. Signature *pSignature = reinterpret_cast<Signature *>(pchSignature);
  287. return pSignature;
  288. }
  289. /* ------------------------------------------------------------ */
  290. /* -------------- memory allocation and stamping -------------- */
  291. /* ------------------------------------------------------------ */
  292. /* ---------------------------------------- TrackMalloc */
  293. void *TrackMalloc(size_t size)
  294. {
  295. // Allocate the memory, including space for the prolog.
  296. PrologChunk *pProlog = (PrologChunk *)malloc(SIZE_PrologChunk + size);
  297. // If the allocation failed, then return NULL.
  298. if (pProlog == NULL) return NULL;
  299. // Use placement new to construct the block header in place.
  300. BlockHeader *pBlockHeader = new (pProlog) BlockHeader(size);
  301. // Link the block header into the list of extant block headers.
  302. BlockHeader::AddNode(pBlockHeader);
  303. // Use placement new to construct the signature in place.
  304. Signature *pSignature = new (GetSignatureAddress(pProlog)) Signature;
  305. // Get the offset to the user chunk and return it.
  306. UserChunk *pUser = GetUserAddress(pProlog);
  307. currentMemorySize += size ;
  308. if (currentMemorySize>maxMemorySize) maxMemorySize=currentMemorySize ;
  309. return pUser;
  310. }
  311. /* ---------------------------------------- TrackFree */
  312. void TrackFree(void *p)
  313. {
  314. // It's perfectly valid for "p" to be null; return if it is.
  315. if (p == NULL) return;
  316. // Get the prolog address for this memory block.
  317. UserChunk *pUser = reinterpret_cast<UserChunk *>(p);
  318. PrologChunk *pProlog = GetPrologAddress(pUser);
  319. // Check the signature, and if it's invalid, return immediately.
  320. Signature *pSignature = GetSignatureAddress(pProlog);
  321. if (!Signature::IsValidSignature(pSignature)) return;
  322. // Destroy the signature.
  323. pSignature->~Signature();
  324. pSignature = NULL;
  325. // Unlink the block header from the list and destroy it.
  326. BlockHeader *pBlockHeader = GetHeaderAddress(pProlog);
  327. currentMemorySize-=pBlockHeader->GetRequestedSize();
  328. BlockHeader::RemoveNode(pBlockHeader);
  329. pBlockHeader->~BlockHeader();
  330. pBlockHeader = NULL;
  331. // Free the memory block.
  332. free(pProlog);
  333. }
  334. /* ---------------------------------------- TrackStamp */
  335. void TrackStamp(void *p, const MemStamp &stamp, char const *typeName)
  336. {
  337. // Get the header and signature address for this pointer.
  338. UserChunk *pUser = reinterpret_cast<UserChunk *>(p);
  339. PrologChunk *pProlog = GetPrologAddress(pUser);
  340. BlockHeader *pHeader = GetHeaderAddress(pProlog);
  341. Signature *pSignature = GetSignatureAddress(pProlog);
  342. // If the signature is not valid, then return immediately.
  343. if (!Signature::IsValidSignature(pSignature)) return;
  344. // "Stamp" the information onto the header.
  345. pHeader->Stamp(stamp.filename, stamp.lineNum, typeName);
  346. }
  347. /* ---------------------------------------- TrackDumpBlocks */
  348. void TrackDumpBlocks()
  349. {
  350. // Get an array of pointers to all extant blocks.
  351. size_t numBlocks = BlockHeader::CountBlocks();
  352. BlockHeader **ppBlockHeader =
  353. (BlockHeader **)calloc(numBlocks, sizeof(*ppBlockHeader));
  354. BlockHeader::GetBlocks(ppBlockHeader);
  355. // Dump information about the memory blocks.
  356. printf("\n");
  357. printf("=====================\n");
  358. printf("Current Memory Blocks\n");
  359. printf("=====================\n");
  360. printf("\n");
  361. for (size_t i = 0; i < numBlocks; i++)
  362. {
  363. BlockHeader *pBlockHeader = ppBlockHeader[i];
  364. char const *typeName = pBlockHeader->GetTypeName();
  365. size_t size = pBlockHeader->GetRequestedSize();
  366. char const *fileName = pBlockHeader->GetFilename();
  367. int lineNum = pBlockHeader->GetLineNum();
  368. printf("*** #%-6d %5d bytes %-50s\n", i, size, typeName);
  369. printf("... %s:%d\n", fileName, lineNum);
  370. pBlockHeader->backTrace();
  371. }
  372. // Clean up.
  373. free(ppBlockHeader);
  374. }
  375. /* ---------------------------------------- struct MemDigest */
  376. struct MemDigest
  377. {
  378. char const *typeName;
  379. int blockCount;
  380. size_t totalSize;
  381. static bool TotalSizeGreaterThan(const MemDigest &md1, const MemDigest &md2)
  382. { return md1.totalSize > md2.totalSize; }
  383. };
  384. /* ---------------------------------------- SummarizeMemoryUsageForType */
  385. static void SummarizeMemoryUsageForType(
  386. MemDigest *pMemDigest,
  387. BlockHeader **ppBlockHeader,
  388. size_t startPost,
  389. size_t endPost
  390. )
  391. {
  392. pMemDigest->typeName = ppBlockHeader[startPost]->GetTypeName();
  393. pMemDigest->blockCount = 0;
  394. pMemDigest->totalSize = 0;
  395. for (size_t i = startPost; i < endPost; i++)
  396. {
  397. pMemDigest->blockCount++;
  398. pMemDigest->totalSize += ppBlockHeader[i]->GetRequestedSize();
  399. assert(strcmp(ppBlockHeader[i]->GetTypeName(), pMemDigest->typeName) == 0);
  400. }
  401. }
  402. /* ---------------------------------------- TrackListMemoryUsage */
  403. void TrackListMemoryUsage()
  404. {
  405. // If there are no allocated blocks, then return now.
  406. size_t numBlocks = BlockHeader::CountBlocks();
  407. if (numBlocks == 0) return;
  408. // Get an array of pointers to all extant blocks.
  409. BlockHeader **ppBlockHeader =
  410. (BlockHeader **)calloc(numBlocks, sizeof(*ppBlockHeader));
  411. BlockHeader::GetBlocks(ppBlockHeader);
  412. // Sort the blocks by type name.
  413. std::sort(
  414. ppBlockHeader,
  415. ppBlockHeader + numBlocks,
  416. BlockHeader::TypeGreaterThan
  417. );
  418. // Find out how many unique types we have.
  419. size_t numUniqueTypes = 1;
  420. for (size_t i = 1; i < numBlocks; i++)
  421. {
  422. char const *prevTypeName = ppBlockHeader[i - 1]->GetTypeName();
  423. char const *currTypeName = ppBlockHeader[i]->GetTypeName();
  424. if (strcmp(prevTypeName, currTypeName) != 0) numUniqueTypes++;
  425. }
  426. // Create an array of "digests" summarizing memory usage by type.
  427. size_t startPost = 0;
  428. size_t uniqueTypeIndex = 0;
  429. MemDigest *pMemDigestArray =
  430. (MemDigest *)calloc(numUniqueTypes, sizeof(*pMemDigestArray));
  431. for (size_t i = 1; i <= numBlocks; i++) // yes, less than or *equal* to
  432. {
  433. char const *prevTypeName = ppBlockHeader[i - 1]->GetTypeName();
  434. char const *currTypeName = (i < numBlocks) ? ppBlockHeader[i]->GetTypeName() : "";
  435. if (strcmp(prevTypeName, currTypeName) != 0)
  436. {
  437. size_t endPost = i;
  438. SummarizeMemoryUsageForType(
  439. pMemDigestArray + uniqueTypeIndex,
  440. ppBlockHeader,
  441. startPost,
  442. endPost
  443. );
  444. startPost = endPost;
  445. uniqueTypeIndex++;
  446. }
  447. }
  448. assert(uniqueTypeIndex = numUniqueTypes);
  449. // Sort the digests by total memory usage.
  450. std::sort(
  451. pMemDigestArray,
  452. pMemDigestArray + numUniqueTypes,
  453. MemDigest::TotalSizeGreaterThan
  454. );
  455. // Compute the grand total memory usage.
  456. size_t grandTotalNumBlocks = 0;
  457. size_t grandTotalSize = 0;
  458. for (size_t i = 0; i < numUniqueTypes; i++)
  459. {
  460. grandTotalNumBlocks += pMemDigestArray[i].blockCount;
  461. grandTotalSize += pMemDigestArray[i].totalSize;
  462. }
  463. // Dump the memory usage statistics.
  464. printf("\n");
  465. printf("-----------------------\n");
  466. printf("Memory Usage Statistics\n");
  467. printf("-----------------------\n");
  468. printf("\n");
  469. printf("%-50s%5s %5s %7s %s \n", "allocated type", "blocks", "", "bytes", "");
  470. printf("%-50s%5s %5s %7s %s \n", "--------------", "------", "", "-----", "");
  471. for (size_t i = 0; i < numUniqueTypes; i++)
  472. {
  473. MemDigest *pMD = pMemDigestArray + i;
  474. size_t blockCount = pMD->blockCount;
  475. double blockCountPct = 100.0 * blockCount / grandTotalNumBlocks;
  476. size_t totalSize = pMD->totalSize;
  477. double totalSizePct = 100.0 * totalSize / grandTotalSize;
  478. printf(
  479. "%-50s %5d %5.1f%% %7d %5.1f%%\n",
  480. pMD->typeName,
  481. blockCount,
  482. blockCountPct,
  483. totalSize,
  484. totalSizePct
  485. );
  486. }
  487. printf("%-50s %5s %5s %7s %s \n", "--------", "-----", "", "-------", "");
  488. printf("%-50s %5d %5s %7d %s \n", "[totals]", grandTotalNumBlocks, "", grandTotalSize, "");
  489. // Clean up.
  490. free(ppBlockHeader);
  491. free(pMemDigestArray);
  492. }
  493. } // namespace MemTrack
  494. /* ------------------------------------------------------------ */
  495. /* ---------------------- new and delete ---------------------- */
  496. /* ------------------------------------------------------------ */
  497. /* ---------------------------------------- operator new */
  498. void *operator new(size_t size)
  499. {
  500. void *p = MemTrack::TrackMalloc(size);
  501. if (p == NULL) throw std::bad_alloc();
  502. return p;
  503. }
  504. /* ---------------------------------------- operator delete */
  505. void operator delete(void *p)
  506. {
  507. MemTrack::TrackFree(p);
  508. }
  509. /* ---------------------------------------- operator new[] */
  510. void *operator new[](size_t size)
  511. {
  512. void *p = MemTrack::TrackMalloc(size);
  513. if (p == NULL) throw std::bad_alloc();
  514. return p;
  515. }
  516. /* ---------------------------------------- operator delete[] */
  517. void operator delete[](void *p)
  518. {
  519. MemTrack::TrackFree(p);
  520. }
  521. #endif