00001
00002
00016
00017
00018
00019
00020 #pragma once
00021
00022 #include "Setup.h"
00023
00024
00025
00026 #if defined(_DEBUG) || defined(ENABLE_MEMMAN_TRACE_IN_RELEASE)
00027 #define MEMMAN_TRACING
00028 #endif
00029
00030
00031
00032
00033
00034
00035 #include <list>
00036 #include <string>
00037 #include "Types.h"
00038 #include "Locks.h"
00039
00040
00041 enum EMemAllocType
00042 {
00043 EMAT_None,
00044 EMAT_One,
00045 EMAT_Array
00046 };
00047
00049 class MemMan
00050 {
00051 public:
00052 MemMan();
00053 ~MemMan();
00054
00056 void AddLeakReportCallback(void (*leakCallback)(const std::string &leakMessage));
00057
00058
00059 void CheckForPaddingCorruption();
00060
00061
00062
00063 int HintMemAlloc(int bytes);
00064
00065 void HintMemFree(int ID);
00066
00067
00068 inline bool IsReady() const
00069 { return m_ready; }
00070
00071
00072 void TraceAlloc(EMemAllocType type, volatile void *addr, void *allocMem, uint size, const char *name, const char *file, int line, int count);
00073 EMemAllocType TraceFree(EMemAllocType type, volatile void *addr, const char *file, int line, char *&outAllocMem, int *outCount=0);
00074
00075
00076 char* InternalAllocBlock(uint bytes);
00077 void InternalFreeBlock(volatile char *mem);
00078 void InternalInitialize();
00079 void InternalShutdown();
00080
00081 #ifdef MEMMAN_TRACING // -- if using management --
00082
00083 struct SAlloc
00084 {
00085 EMemAllocType type;
00086 void *addr;
00087 void *allocMem;
00088 uint size;
00089 std::string objName;
00090 std::string srcFile;
00091 int srcLine;
00092 int count;
00093 std::string allocStack;
00094 std::string deleteStack;
00095
00096 SAlloc *next;
00097 };
00098
00099 private:
00100 bool m_critErrors;
00101
00102 SAlloc *m_head;
00103
00104
00105
00106 int maxMem;
00107 void RecalcMaxMem();
00108
00109 int curHintAllocID;
00110
00111 struct Hint
00112 {
00113 int ID;
00114 int bytes;
00115 std::string stack;
00116 };
00117 std::list<Hint> hints;
00118
00119 #endif //tracing
00120
00121
00122 void ReportLeak(const std::string &leak);
00123 std::list<void (*)(const std::string &)> leakCallbacks;
00124
00125 bool m_ready;
00126 MPMA::MutexLock *syncLock;
00127
00128 public:
00129
00130 template <typename T> static void dbgN2_Destruct(T *obj)
00131 {
00132 obj->~T();
00133 }
00134 template <typename T> static void dbgN2_Destruct_array(T *obj, int count)
00135 {
00136 for (int i=0; i<count; ++i)
00137 {
00138 obj->~T();
00139 ++obj;
00140 }
00141 }
00142 };
00143
00144 extern MemMan mMan;
00145
00146 #ifdef MEMMAN_TRACING // -- if using management --
00147
00148
00149 #define dbgN2_padding 8
00150
00151
00152
00153 template <typename AllocType> AllocType* new2_call(AllocType *obj, const char *name, const char *file, int line)
00154 {
00155 mMan.TraceAlloc(EMAT_One, obj, (char*)obj-dbgN2_padding, sizeof(AllocType), name, file, line, 1);
00156 return obj;
00157 }
00158
00159 template <typename AllocType> AllocType* new2_array_call(size_t count, const char *name, const char *file, int line)
00160 {
00161
00162 char *realMem=mMan.InternalAllocBlock(sizeof(AllocType)*count + dbgN2_padding*2);
00163 char *allocSpot=realMem+dbgN2_padding;
00164 AllocType *obj=new (allocSpot) AllocType[count];
00165
00166 mMan.TraceAlloc(EMAT_Array, obj, realMem, sizeof(AllocType)*count, name, file, line, (int)count);
00167 return obj;
00168 }
00169
00170 #endif
00171
00172 #ifdef MEMMAN_TRACING // -- if using management --
00173
00174
00175 void dbgN2_PrecheckType(const char *objName, const char *typName);
00176
00177
00178
00179 #define delete2_call(obj,pMem,file,line) \
00180 do { \
00181 int count=0; \
00182 char *realMem=0; \
00183 EMemAllocType type=mMan.TraceFree(EMAT_One, obj, file, line, realMem,&count); \
00184 if (type==EMAT_One) MemMan::dbgN2_Destruct(obj); \
00185 else if (type==EMAT_Array) MemMan::dbgN2_Destruct_array(obj,count); \
00186 mMan.InternalFreeBlock(realMem); \
00187 *((uint**)(pMem))=(uint*)-1; \
00188 } while(false)
00189
00190 #define delete2_array_call(obj,pMem,file,line) \
00191 do { \
00192 int count=0; \
00193 char *realMem=0; \
00194 EMemAllocType type=mMan.TraceFree(EMAT_Array, obj, file, line, realMem, &count); \
00195 if (type==EMAT_One) MemMan::dbgN2_Destruct(obj); \
00196 else if (type==EMAT_Array) MemMan::dbgN2_Destruct_array(obj,count); \
00197 mMan.InternalFreeBlock(realMem); \
00198 *((uint**)(pMem))=(uint*)-1; \
00199 } while(false)
00200
00201
00202
00203
00205 #define new2(obj,type) (dbgN2_PrecheckType(""#obj,""#type), new2_call(new (mMan.InternalAllocBlock(dbgN2_padding*2+sizeof(type))+dbgN2_padding) obj, ""#obj, __FILE__, __LINE__))
00207 #define new2_array(obj,count,type) (dbgN2_PrecheckType(""#obj,""#type), new2_array_call<type>(count, ""#obj, __FILE__, __LINE__))
00208
00210 #define delete2(obj) delete2_call(obj,(void**)&obj,__FILE__,__LINE__)
00212 #define delete2_array(obj) delete2_array_call(obj,(void**)&obj,__FILE__,__LINE__)
00213
00214 #define hint_mem_alloc(bytes) mMan.HintMemAlloc(bytes)
00215 #define hint_mem_free(ID) mMan.HintMemFree(ID)
00216
00217 #else // -- if NOT using management
00218
00219 #ifdef NEEDS_THREADSAFE_ALLOC //if our platform doesn't have threadsafe new and delete
00220
00221 #define new2(obj,type) new (mMan.InternalAllocBlock(sizeof(type))) obj
00222
00223 inline char* MemMan_InjectIntBeforeArray(char *mem, uint count)
00224 {
00225 *(uint*)mem=count;
00226 return mem + sizeof(uint);
00227 }
00228
00229 #define new2_array(obj,count,type) new (MemMan_InjectIntBeforeArray(mMan.InternalAllocBlock(sizeof(type)*count + sizeof(uint)), count)) obj
00230
00231 #define delete2(obj) do {\
00232 MemMan::dbgN2_Destruct(obj); \
00233 mMan.InternalFreeBlock((volatile char*)obj); } while(false)
00234
00235 #define delete2_array(obj) do {\
00236 MemMan::dbgN2_Destruct_array(obj,*((uint*)obj-1)); \
00237 mMan.InternalFreeBlock((volatile char*)obj - sizeof(uint)); } while(false)
00238
00239
00240 #else //platform has threadsafe new and delete already
00241
00242 #define new2(obj,junk) new obj
00243 #define new2_array(obj,count,junk) new obj[count]
00244
00245 #define delete2(obj) delete obj
00246 #define delete2_array(obj) delete[] obj
00247
00248 #endif
00249
00250 #define hint_mem_alloc(bytes) 0
00251 #define hint_mem_free(ID)
00252
00253 #endif //(build check)
00254
00255
00256
00257
00258
00259
00261 template <typename T>
00262 class AutoDelete
00263 {
00264 public:
00265 inline AutoDelete(T *inPtr): ptr(inPtr) {}
00266 inline ~AutoDelete() {if (ptr) delete2(ptr);}
00267 private:
00268 T *ptr;
00269 };
00270
00272 template <typename T>
00273 class AutoDeleteArray
00274 {
00275 public:
00276 inline AutoDeleteArray(T *inPtr): ptr(inPtr) {}
00277 inline ~AutoDeleteArray() {if (ptr) delete2_array(ptr);}
00278 private:
00279 T *ptr;
00280 };