SpMemory.cpp
上传用户:zhanglf88
上传日期:2013-11-19
资源大小:6036k
文件大小:12k
源码类别:

金融证券系统

开发平台:

Visual C++

  1. /*
  2. Cross Platform Core Code.
  3. Copyright(R) 2001-2002 Balang Software.
  4. All rights reserved.
  5. Using:
  6. operator new;
  7. operator delete;
  8. other memory method.
  9. */
  10. #include "StdAfx.h"
  11. #include "SPLock.h"
  12. #ifdef _DEBUG
  13. #undef THIS_FILE
  14. static char THIS_FILE[] = __FILE__;
  15. #endif
  16. // WARNING: Debug版对内存的处理,不支持线程同步,所以可能会出问题,但是不影响Release版
  17. #if defined(_DEBUG) && !defined(_AFX)
  18. void* operator new(size_t nSize)
  19. {
  20. void* p = SP_AllocMemoryDebug(nSize, FALSE, NULL, 0);
  21. if (p == NULL)
  22. {
  23. SP_TRACE1("::operator new(%u) failed - throwing exceptionn", nSize);
  24. SP_ASSERT( FALSE );
  25. }
  26. return p;
  27. }
  28. void* operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
  29. {
  30. void* p = SP_AllocMemoryDebug(nSize, FALSE, lpszFileName, nLine);
  31. if (p == NULL)
  32. {
  33. SP_TRACE1("::operator new(%u) failed - throwing exceptionn", nSize);
  34. SP_ASSERT( FALSE );
  35. }
  36. return p;
  37. }
  38. #if _MSC_VER>=1200
  39. void operator delete(void *pMem, LPCSTR lpszFileName, int nLine )
  40. {
  41. SP_ASSERT( SP_CheckMemory() );
  42. SP_FreeMemoryDebug(pMem, FALSE);
  43. }
  44. #endif
  45. void operator delete(void* pbData)
  46. {
  47. SP_FreeMemoryDebug(pbData, FALSE);
  48. }
  49. #endif
  50. #ifdef _DEBUG
  51. #define SIZE_T_MAX UINT_MAX
  52. static LONG  lTotalAlloc;
  53. static LONG  lCurAlloc;
  54. static LONG  lMaxAlloc;
  55. static BOOL bTrackingOn = TRUE;
  56. static LONG  lRequestLast = 0;
  57. #define lNotTracked 0
  58. struct CBlockHeader;
  59. static struct CBlockHeader*  pFirstBlock = NULL;
  60. static CSPMutex g_mutexBlockChain;
  61. static char  szFree[] = "Free";
  62. static char  szObject[] = "Object";
  63. static char  szNonObject[] = "Non-Object";
  64. static char  szDamage[] = "Damage";
  65. #define nNoMansLandSize     4
  66. #define bNoMansLandFill     0xFD
  67. #define bDeadLandFill       0xDD
  68. #define bCleanLandFill      0xCD
  69. struct CBlockHeader
  70. {
  71. struct CBlockHeader* pBlockHeaderNext;
  72. struct CBlockHeader* pBlockHeaderPrev;
  73. LPCSTR              lpszFileName;
  74. int                 nLine;
  75. size_t              nDataSize;
  76. enum CSPMemoryState::blockUsage use;
  77. LONG                lRequest;
  78. BYTE                gap[nNoMansLandSize];
  79. BYTE* pbData()
  80. { return (BYTE*) (this + 1); }
  81. };
  82. static LPCSTR  blockUseName[CSPMemoryState::nBlockUseMax] =
  83. { szFree, szObject, szNonObject };
  84. static LONG _afxBreakAlloc = -1;
  85. void*  SP_AllocMemoryDebug(size_t nSize, BOOL bIsObject, LPCSTR lpszFileName, int nLine)
  86. {
  87. SP_ASSERT(nSize > 0);
  88. LONG    lRequest;
  89. lRequest = bTrackingOn ? ++lRequestLast : lNotTracked;
  90. if (nSize > (size_t)SIZE_T_MAX - nNoMansLandSize - sizeof(CBlockHeader))
  91. {
  92. SP_TRACE1("Error: memory allocation: tried to allocate %u bytesn", nSize);
  93. }
  94. lTotalAlloc += nSize;
  95. lCurAlloc += nSize;
  96. if (lCurAlloc > lMaxAlloc)
  97. lMaxAlloc = lCurAlloc;
  98. struct CBlockHeader* p = (struct CBlockHeader*)
  99.    malloc(sizeof(CBlockHeader) + nSize + nNoMansLandSize);
  100. if (p == NULL)
  101. return NULL;
  102. CSPMutex::Scoped locker(g_mutexBlockChain);
  103. if (pFirstBlock)
  104. pFirstBlock->pBlockHeaderPrev = p;
  105. p->pBlockHeaderNext = pFirstBlock;
  106. p->pBlockHeaderPrev = NULL;
  107. p->lpszFileName = lpszFileName;
  108. p->nLine = nLine;
  109. p->nDataSize = nSize;
  110. p->use = bIsObject ? CSPMemoryState::objectBlock : CSPMemoryState::bitBlock;
  111. p->lRequest = lRequest;
  112. memset(p->gap, bNoMansLandFill, nNoMansLandSize);
  113. memset(p->pbData() + nSize, bNoMansLandFill, nNoMansLandSize);
  114. memset(p->pbData(), bCleanLandFill, nSize);
  115. pFirstBlock = p;
  116. return (void*)p->pbData();
  117. }
  118. void  SP_FreeMemoryDebug(void* pbData, BOOL bIsObject)
  119. {
  120. if (pbData == NULL)
  121. return;
  122. struct CBlockHeader* p = ((struct CBlockHeader*) pbData)-1;
  123. SP_ASSERT(p->use == (bIsObject ? CSPMemoryState::objectBlock
  124. : CSPMemoryState::bitBlock));
  125. lCurAlloc -= p->nDataSize;
  126. p->use = CSPMemoryState::freeBlock;
  127. CSPMutex::Scoped locker(g_mutexBlockChain);
  128. if (p->pBlockHeaderNext)
  129. p->pBlockHeaderNext->pBlockHeaderPrev = p->pBlockHeaderPrev;
  130. if (p->pBlockHeaderPrev)
  131. {
  132. p->pBlockHeaderPrev->pBlockHeaderNext = p->pBlockHeaderNext;
  133. }
  134. else
  135. {
  136. SP_ASSERT(pFirstBlock == p);
  137. if( pFirstBlock == p )
  138. pFirstBlock = p->pBlockHeaderNext;
  139. }
  140. memset(p, bDeadLandFill,
  141. sizeof(CBlockHeader) + p->nDataSize + nNoMansLandSize);
  142. free(p);
  143. }
  144. void *SP_ReAllocMemoryDebug( void *pbData, size_t nSize, BOOL bObject, LPCSTR lpszFileName, int nLine )
  145. {
  146. void *p;
  147. struct CBlockHeader* p1 = ((struct CBlockHeader*) pbData)-1;
  148. p = SP_AllocMemoryDebug( nSize, bObject, lpszFileName, nLine );
  149. if( NULL == p )
  150. {
  151. SP_TRACE0("alloc Memory fail!.");
  152. return pbData;
  153. }
  154. memcpy(p, pbData, min( nSize, p1->nDataSize) );
  155. SP_FreeMemoryDebug( pbData, FALSE );
  156. return p;
  157. }
  158. static BOOL CheckBytes(BYTE* pb, WORD bCheck, size_t nSize)
  159. {
  160. BOOL bOkay = TRUE;
  161. while (nSize--)
  162. {
  163. if (*pb++ != bCheck)
  164. {
  165. SP_TRACE3("memory check error at $%08lX = $%02X, should be $%02Xn",
  166. (BYTE *) (pb-1),*(pb-1), bCheck);
  167. bOkay = FALSE;
  168. }
  169. }
  170. return bOkay;
  171. }
  172. BOOL SP_CheckMemory()
  173. {
  174. CSPMutex::Scoped locker(g_mutexBlockChain);
  175. BOOL    allOkay = TRUE;
  176. struct CBlockHeader* p;
  177. for (p = pFirstBlock; p != NULL; p = p->pBlockHeaderNext)
  178. {
  179. BOOL okay = TRUE;
  180. LPCSTR blockUse;
  181. if (p->use >= 0 && p->use < CSPMemoryState::nBlockUseMax)
  182. blockUse = blockUseName[p->use];
  183. else
  184. blockUse = szDamage;
  185. if (!CheckBytes(p->gap, bNoMansLandFill, nNoMansLandSize))
  186. {
  187. SP_TRACE2("DAMAGE: before %Fs block at $%08lXn", blockUse,
  188. (BYTE *) p->pbData());
  189. okay = FALSE;
  190. }
  191. if (!CheckBytes(p->pbData() + p->nDataSize, bNoMansLandFill,
  192.   nNoMansLandSize))
  193. {
  194. SP_TRACE2("DAMAGE: after %Fs block at $%08lXn", blockUse,
  195. (BYTE *) p->pbData());
  196. okay = FALSE;
  197. }
  198. if (p->use == CSPMemoryState::freeBlock &&
  199.   !CheckBytes(p->pbData(), bDeadLandFill, p->nDataSize))
  200. {
  201. SP_TRACE1("DAMAGE: on top of Free block at $%08lXn",
  202. (BYTE *) p->pbData());
  203. okay = FALSE;
  204. }
  205. if (!okay)
  206. {
  207. if (p->lpszFileName != NULL)
  208. SP_TRACE3("%Fs allocated at file %Fs(%d)n", blockUse,
  209. p->lpszFileName, p->nLine);
  210. SP_TRACE3("%Fs located at $%08lX is %u bytes longn", blockUse,
  211. (BYTE *) p->pbData(), p->nDataSize);
  212. allOkay = FALSE;
  213. }
  214. }
  215. return allOkay;
  216. }
  217. void  SP_ExitCheckMemory()
  218. {
  219. CSPMutex::Scoped locker(g_mutexBlockChain);
  220. struct CBlockHeader* p;
  221. if( pFirstBlock )
  222. {
  223. SP_TRACE0("----------------------------!!!Warning!!!-----------------------n");
  224. SP_TRACE0("Detect memory leaked!n");
  225. }
  226. for (p = pFirstBlock; p != NULL; p = p->pBlockHeaderNext)
  227. {
  228. LPCSTR blockUse;
  229. if (p->use >= 0 && p->use < CSPMemoryState::nBlockUseMax)
  230. blockUse = blockUseName[p->use];
  231. else
  232. blockUse = szDamage;
  233. if (p->lpszFileName != NULL)
  234. {
  235. SP_TRACE3("%Fs allocated at file %Fs(%d).", blockUse,
  236. p->lpszFileName, p->nLine);
  237. }
  238. SP_TRACE3("%Fs located at $%08lX is %u bytes long.", blockUse,
  239. (BYTE *) p->pbData(), p->nDataSize);
  240. }
  241. }
  242. /////////////////////////////////////////////////////////////////////////////
  243. // CSPMemoryState
  244. CSPMemoryState::CSPMemoryState()
  245. {
  246. m_pBlockHeader = NULL;
  247. }
  248. // fills 'this' with the difference, returns TRUE if significant
  249. BOOL CSPMemoryState::Difference(const CSPMemoryState& oldState,
  250. const CSPMemoryState& newState)
  251. {
  252. BOOL bSignificantDifference = FALSE;
  253. for (int use = 0; use < CSPMemoryState::nBlockUseMax; use++)
  254. {
  255. m_lSizes[use] = newState.m_lSizes[use] - oldState.m_lSizes[use];
  256. m_lCounts[use] = newState.m_lCounts[use] - oldState.m_lCounts[use];
  257. if ((m_lSizes[use] != 0 || m_lCounts[use] != 0) &&
  258.   use != CSPMemoryState::freeBlock)
  259. bSignificantDifference = TRUE;
  260. }
  261. m_lHighWaterCount = newState.m_lHighWaterCount - oldState.m_lHighWaterCount;
  262. m_lTotalCount = newState.m_lTotalCount - oldState.m_lTotalCount;
  263. return bSignificantDifference;
  264. }
  265. void CSPMemoryState::DumpStatistics() const
  266. {
  267. for (int use = 0; use < CSPMemoryState::nBlockUseMax; use++)
  268. {
  269. SP_TRACE3("%ld bytes in %ld %Fs Blocksn", m_lSizes[use],
  270. m_lCounts[use], blockUseName[use]);
  271. }
  272. SP_TRACE1("Largest number used: %ld bytesn", m_lHighWaterCount);
  273. SP_TRACE1("Total allocations: %ld bytesn", m_lTotalCount);
  274. }
  275. // -- fill with current memory state
  276. void CSPMemoryState::Checkpoint()
  277. {
  278. CSPMutex::Scoped locker(g_mutexBlockChain);
  279. m_pBlockHeader = pFirstBlock;
  280. for (int use = 0; use < CSPMemoryState::nBlockUseMax; use++)
  281. m_lCounts[use] = m_lSizes[use] = 0;
  282. struct CBlockHeader* p;
  283. for (p = pFirstBlock; p != NULL; p = p->pBlockHeaderNext)
  284. {
  285. if (p->lRequest == lNotTracked)
  286. {
  287. // ignore it for statistics
  288. }
  289. else if (p->use >= 0 && p->use < CSPMemoryState::nBlockUseMax)
  290. {
  291. m_lCounts[p->use]++;
  292. m_lSizes[p->use] += p->nDataSize;
  293. }
  294. else
  295. {
  296. SP_TRACE1("Bad memory block found at $%08lXn", (BYTE*) p);
  297. }
  298. }
  299. m_lHighWaterCount = lMaxAlloc;
  300. m_lTotalCount = lTotalAlloc;
  301. }
  302. // Dump objects created after this memory state was checkpointed
  303. // Will dump all objects if this memory state wasn't checkpointed
  304. // Dump all objects, report about non-objects also
  305. // List request number in {}
  306. void CSPMemoryState::DumpAllObjectsSince() const
  307. {
  308. CSPMutex::Scoped locker(g_mutexBlockChain);
  309. struct CBlockHeader* pBlockStop;
  310. SP_TRACE0("<Spring> Dumping objects ->n");
  311. pBlockStop = m_pBlockHeader;
  312. struct CBlockHeader* p;
  313. for (p = pFirstBlock; p != NULL && p != pBlockStop;
  314. p = p->pBlockHeaderNext)
  315. {
  316. char sz[255];
  317. if (p->lRequest == lNotTracked)
  318. {
  319. // ignore it for dumping
  320. }
  321. else if (p->use == CSPMemoryState::objectBlock)
  322. {
  323. Object* pObject = (Object*) p->pbData();
  324. SP_TRACE1("{%ld} ", p->lRequest);
  325. if (p->lpszFileName != NULL)
  326. {
  327. if (!SP_IsValidAddress( (void*)(p->lpszFileName), 1, FALSE))
  328. sprintf(sz, "#File Error#(%d) : ", p->nLine);
  329. else
  330. sprintf(sz, "%Fs(%d) : ", p->lpszFileName, p->nLine);
  331. SP_OutputDebugString( (LPCSTR)sz );
  332. }
  333. #if !defined(_NEARDATA) || defined(_M_I86MM)
  334. // with large vtable, verify that object and vtable are valid
  335. if (!SP_IsValidAddress(*(void FAR**)pObject, sizeof(void FAR*), FALSE) )
  336. #else
  337. // with near vtable, verify that object and vtable are valid
  338. if (!SP_IsValidAddress(*(void**)pObject, sizeof(void*), FALSE) )
  339. #endif
  340. {
  341. // short form for trashed objects
  342. sprintf(sz, "an invalid object at $%08lX, %u bytes longn",
  343. (BYTE FAR*) p->pbData(), p->nDataSize);
  344. SP_OutputDebugString( (LPCSTR)sz );
  345. }
  346. else 
  347. {
  348. // short form
  349. sprintf(sz, "a object at $%08lX, %u bytes longn",
  350. (BYTE FAR*) p->pbData(), p->nDataSize);
  351. SP_OutputDebugString( (LPCSTR)sz );
  352. pObject->Dump();
  353. }
  354. }
  355. else if (p->use == CSPMemoryState::bitBlock)
  356. {
  357. SP_TRACE1("{%ld} ", p->lRequest);
  358. if (p->lpszFileName != NULL)
  359. {
  360. if (NULL == p->lpszFileName)
  361. sprintf(sz, "#File Error#(%d) : ", p->nLine);
  362. else
  363. sprintf(sz, "%Fs(%d) : ", p->lpszFileName, p->nLine);
  364. SP_OutputDebugString( (LPCSTR)sz );
  365. }
  366. sprintf(sz, "non-object block at $%08lX, %u bytes longn",
  367. (BYTE *) p->pbData(), p->nDataSize);
  368. SP_OutputDebugString( (LPCSTR)sz );
  369. }
  370. }
  371. SP_TRACE0("<Spring> Object dump complete.nn");
  372. }
  373. #ifdef SP_WINDOWS // SP_EXITDUMP comes too late for non-Windows app termination
  374. class SP_EXITDUMP
  375. {
  376. public:
  377. ~SP_EXITDUMP();
  378. };
  379. SP_EXITDUMP::~SP_EXITDUMP()
  380. {
  381. // only dump leaks when there are in fact leaks
  382. CSPMemoryState msNow;
  383. msNow.Checkpoint();
  384. if (msNow.m_lCounts[CSPMemoryState::objectBlock] != 0 ||
  385. msNow.m_lCounts[CSPMemoryState::bitBlock] != 0)
  386. {
  387. // dump objects since empty state since difference detected.
  388. SP_TRACE0("----------------------------!!!Warning!!!-----------------------n");
  389. SP_TRACE0("-<Spring>-  Detected memory leaks!n");
  390. CSPMemoryState msEmpty;   // construct empty memory state object
  391. msEmpty.DumpAllObjectsSince();
  392. }
  393. }
  394. static SP_EXITDUMP SP_ExitDump;
  395. #endif //_WINDOWS
  396. #else
  397. static void*  SP_AllocMemoryDebug(size_t nSize, BOOL bIsObject, LPCSTR lpszFileName, int nLine)
  398. {
  399. return malloc( nSize );
  400. }
  401. static void  SP_FreeMemoryDebug(void* pbData, BOOL bIsObject)
  402. {
  403. free( pbData );
  404. }
  405. #endif//_DEBUG