1 /*
2 * memstats.cpp
3 * OpenLieroX
4 *
5 * memstats implementation for memstats.h
6 *
7 * Created by Albert Zeyer on 03.09.09.
8 * code under LGPL
9 *
10 */
11
12 #ifdef MEMSTATS
13
14 #include <new>
15 #include <iostream>
16 #include <map>
17 #include <string>
18 #include "Debug.h"
19 #include "Mutex.h"
20
21 #undef new
22 #undef delete
23
24 #define SAFEALLOC_MAXALLOCS (1024 * 1024)
25 #define SAFEALLOC_POOLSIZE (50 * 1024 * 1024)
26
27 struct SafeAlloc {
28 char* p;
29 size_t s;
30 SafeAlloc *left, *right;
31
SafeAllocSafeAlloc32 SafeAlloc() : p(NULL), s(0), left(NULL), right(NULL) {}
isUsedSafeAlloc33 bool isUsed() const { return p != NULL; }
resetSafeAlloc34 void reset() { p = NULL; s = 0; left = NULL; right = NULL; }
initPoolMemSafeAlloc35 void initPoolMem() { *(SafeAlloc**)p = this; }
userPtSafeAlloc36 void* userPt() const { return p + extraSpacePerAlloc; }
userSizeSafeAlloc37 size_t userSize() const { return s - SafeAlloc::extraSpacePerAlloc; }
38
39 static const size_t extraSpacePerAlloc = sizeof(SafeAlloc*);
40 };
41
42 static SafeAlloc* safeAllocs = NULL; // sorted list
43 static char safeAllocs_Mem[SAFEALLOC_MAXALLOCS * sizeof(SafeAlloc)];
44 static SafeAlloc *safeAlloc_first = NULL;
45 static SafeAlloc *safeAlloc_lastAlloc = NULL;
46 static char safeAllocPool[SAFEALLOC_POOLSIZE];
47 static Mutex* safeAlloc_mutex = NULL;
48 static char safeAlloc_mutex_Mem[sizeof(Mutex)];
49
safeAlloc_init()50 void safeAlloc_init() {
51 safeAlloc_mutex = (Mutex*) &safeAlloc_mutex_Mem[0];
52 new (safeAlloc_mutex) Mutex;
53
54 safeAllocs = (SafeAlloc*) &safeAllocs_Mem[0];
55 for(size_t i = 0; i < SAFEALLOC_MAXALLOCS; ++i)
56 new (&safeAllocs[i]) SafeAlloc;
57 }
58
safeAlloc_uninit()59 void safeAlloc_uninit() {
60 for(size_t i = 0; i < SAFEALLOC_MAXALLOCS; ++i)
61 safeAllocs[i] . ~SafeAlloc();
62 safeAllocs = NULL;
63 safeAlloc_mutex -> ~Mutex();
64 safeAlloc_mutex = NULL;
65 }
66
safeAlloc_listEmpty()67 bool safeAlloc_listEmpty() { return safeAlloc_first == NULL; }
68
safeAlloc_allocNum(SafeAlloc * a)69 int safeAlloc_allocNum(SafeAlloc* a) { return int(a - &safeAllocs[0]); }
70
safeAlloc_dbg(const char * txt,SafeAlloc * a)71 void safeAlloc_dbg(const char* txt, SafeAlloc* a) {
72 printf("%s alloc %i @%i (#%i) for %i bytes\n",
73 txt,
74 safeAlloc_allocNum(a),
75 int(a->userPt()),
76 int(a->p - &safeAllocPool[0]),
77 int(a->userSize()));
78 }
79
safeAlloc_sanityCheck(SafeAlloc * a)80 size_t safeAlloc_sanityCheck(SafeAlloc* a) {
81 if(a < &safeAllocs[0]) {
82 printf("wrong: alloc @%i is left outside array\n", int(a));
83 return 0;
84 }
85
86 if(a >= &safeAllocs[SAFEALLOC_MAXALLOCS]) {
87 printf("wrong: alloc @%i is right outside array\n", int(a));
88 return 0;
89 }
90
91 if(a->isUsed()) {
92 if(a->s <= SafeAlloc::extraSpacePerAlloc) printf("wrong: alloc %i has invalid size %i\n", safeAlloc_allocNum(a), a->s);
93 if(a->left >= a) printf("wrong: alloc %i has invalid left link\n", safeAlloc_allocNum(a));
94 if(a->left == NULL && safeAlloc_first != a) printf("wrong: alloc %i has no left link\n", safeAlloc_allocNum(a));
95 if(a->right != NULL && a->right <= a) printf("wrong: alloc %i has invalid right link\n", safeAlloc_allocNum(a));
96
97 // all right followers MUST be used
98 size_t allocNum = 1;
99 for(SafeAlloc* b = a; ; ) {
100 if(!b->isUsed()) {
101 printf("wrong: alloc %i has unused right follower %i\n", safeAlloc_allocNum(a), safeAlloc_allocNum(b));
102 break;
103 }
104 if(b->right == NULL) {
105 // all next items in array must be unused
106 for(SafeAlloc* c = b + 1; c < &safeAllocs[SAFEALLOC_MAXALLOCS]; ++c) {
107 if(c->isUsed()) {
108 printf("wrong: alloc %i has used past-end %i right follower %i\n", safeAlloc_allocNum(a), safeAlloc_allocNum(b), safeAlloc_allocNum(c));
109 break;
110 }
111 }
112 break;
113 }
114 b = b->right;
115 allocNum++;
116 }
117 return allocNum;
118 }
119 else {
120 if(a->s != 0) printf("wrong: unused alloc %i has size = %i\n", safeAlloc_allocNum(a), a->s);
121 if(a->left != NULL) {
122 printf("wrong: unused alloc %i has left link\n", safeAlloc_allocNum(a));
123 if(a->left >= a) printf("wrong: unused alloc %i has invalid left link\n", safeAlloc_allocNum(a));
124 }
125 if(a->right != NULL) {
126 printf("wrong: unused alloc %i has right link\n", safeAlloc_allocNum(a));
127 if(a->right <= a) printf("wrong: unused alloc %i has invalid right link\n", safeAlloc_allocNum(a));
128 }
129 }
130
131 return 0;
132 }
133
safeAlloc_sanityCheckAll()134 void safeAlloc_sanityCheckAll() {
135 size_t allocNum = 0;
136 for(size_t i = 0; i < SAFEALLOC_MAXALLOCS; ++i) {
137 safeAlloc_sanityCheck(&safeAllocs[i]);
138 if(safeAllocs[i].isUsed()) allocNum++;
139 }
140
141 if(!safeAlloc_listEmpty()) {
142 if(!safeAlloc_first->isUsed()) printf("wrong: first alloc %i is unused\n", safeAlloc_allocNum(safeAlloc_first));
143
144 size_t allocNum2 = safeAlloc_sanityCheck(safeAlloc_first);
145 if(allocNum != allocNum2) printf("wrong: absolute allocs (%i) is different than linked list allocs (%i)\n", allocNum, allocNum2);
146 }
147 }
148
149 typedef std::pair<SafeAlloc*,SafeAlloc*> LRpair;
150
safeAlloc_findFreeAt(SafeAlloc * start,size_t n)151 LRpair safeAlloc_findFreeAt(SafeAlloc* start, size_t n) {
152 for(SafeAlloc* a = start; a; a = a->right) {
153 SafeAlloc* b = a->right;
154
155 // Note: obsolete security check
156 if(!a->isUsed()) {
157 printf("SafeAlloc: something is REALLY messed up!\n");
158 printf("sanity check of %i:\n", safeAlloc_allocNum(a));
159 safeAlloc_sanityCheck(a);
160 printf("sanity check everything:\n");
161 safeAlloc_sanityCheckAll();
162 printf("sanity check first (%i):\n", safeAlloc_allocNum(safeAlloc_first));
163 safeAlloc_sanityCheck(safeAlloc_first);
164 safeAlloc_dbg("mess a", a);
165 return LRpair(a, b); // cannot really recover, so who cares...
166 }
167
168 // Note: obsolete security check
169 if(b && !b->isUsed()) {
170 printf("SafeAlloc: something is rightly messed up!\n");
171 safeAlloc_sanityCheck(b);
172 safeAlloc_dbg("mess b", b);
173 return LRpair(a, b); // cannot really recover, so who cares...
174 }
175
176 if(a + 1 == b || a + 1 == &safeAllocs[SAFEALLOC_MAXALLOCS])
177 // we cannot make a list entry here, so continue searching
178 continue;
179
180 const char* rightEnd = b ? b->p : &safeAllocPool[SAFEALLOC_POOLSIZE];
181 char* leftStart = a->p + a->s;
182
183 // Note: obsolete security check
184 if(rightEnd < leftStart) {
185 printf("SafeAlloc: something is messed up!\n");
186 continue; // doesn't really make sense, but we cannot do anything else
187 }
188
189 // Note: obsolete security check
190 if(b && b->left != a) {
191 printf("SafeAlloc: linked list is messed up!\n");
192 }
193
194 const size_t neededSize = n + SafeAlloc::extraSpacePerAlloc;
195 if(size_t(rightEnd - leftStart) >= neededSize)
196 // we have enough place here, return
197 return LRpair(a, b);
198 }
199
200 // nothing free, return invalid pair
201 return LRpair(&safeAllocs[SAFEALLOC_MAXALLOCS], NULL);
202 }
203
safeAlloc_findFree(size_t n)204 LRpair safeAlloc_findFree(size_t n) {
205 if(safeAlloc_listEmpty())
206 return LRpair(NULL, NULL);
207
208 LRpair ret = LRpair(&safeAllocs[SAFEALLOC_MAXALLOCS], NULL);
209 if(safeAlloc_lastAlloc) {
210 ret = safeAlloc_findFreeAt(safeAlloc_lastAlloc, n);
211 if(ret.first < &safeAllocs[SAFEALLOC_MAXALLOCS]) return ret;
212 }
213
214 if(safeAlloc_first > &safeAllocs[0]) {
215 const char* rightEnd = safeAlloc_first->p;
216 char* leftStart = &safeAllocPool[0];
217
218 const size_t neededSize = n + SafeAlloc::extraSpacePerAlloc;
219 if(size_t(rightEnd - leftStart) >= neededSize)
220 // we have enough place here, return
221 return LRpair(NULL, safeAlloc_first);
222 }
223
224 return safeAlloc_findFreeAt(safeAlloc_first, n);
225 }
226
safeAlloc_alloc(size_t n)227 void* safeAlloc_alloc(size_t n) {
228 Mutex::ScopedLock lock(*safeAlloc_mutex);
229 LRpair pair = safeAlloc_findFree(n);
230
231 if(pair.first == NULL) {
232 // everything free or before first entry
233
234 if(n + SafeAlloc::extraSpacePerAlloc > SAFEALLOC_POOLSIZE) {
235 // no chance
236 printf("SafeAlloc alloc: cannot allocate %i bytes, it's more than our whole pool supports\n", n);
237 return NULL;
238 }
239
240 // init list
241 safeAllocs[0].reset();
242 safeAllocs[0].right = safeAlloc_first; if(safeAlloc_first) safeAlloc_first->left = &safeAllocs[0];
243 safeAllocs[0].p = &safeAllocPool[0];
244 safeAllocs[0].s = n + SafeAlloc::extraSpacePerAlloc;
245 safeAllocs[0].initPoolMem();
246 safeAlloc_first = &safeAllocs[0];
247 safeAlloc_lastAlloc = safeAlloc_first;
248 //safeAlloc_dbg("init first", &safeAllocs[0]);
249 return safeAllocs[0].userPt();
250 }
251
252 SafeAlloc* a = pair.first + 1;
253 if(a < &safeAllocs[SAFEALLOC_MAXALLOCS]) {
254 // we fit after pair.first
255
256 a->reset();
257 a->left = pair.first; pair.first->right = a;
258 a->right = pair.second; if(pair.second) pair.second->left = a;
259 a->p = a->left->p + a->left->s; // directly next to the left alloc
260 a->s = n + SafeAlloc::extraSpacePerAlloc;
261 a->initPoolMem();
262 safeAlloc_lastAlloc = a;
263 //safeAlloc_dbg("init", a);
264 return a->userPt();
265 }
266
267 // nothing free
268 printf("SafeAlloc alloc: cannot allocate %i bytes, nothing free anymore\n", n);
269 return NULL;
270 }
271
safeAlloc_free(void * p)272 void safeAlloc_free(void* p) {
273 Mutex::ScopedLock lock(*safeAlloc_mutex);
274
275 if((size_t)p < SafeAlloc::extraSpacePerAlloc) {
276 printf("SafeAlloc free: pointer %i is invalid!\n", int(p));
277 return;
278 }
279
280 SafeAlloc** const a = (SafeAlloc**)p - 1;
281 if((char*)a < &safeAllocPool[0] || (char*)a + sizeof(SafeAlloc*) - 1 >= &safeAllocPool[SAFEALLOC_POOLSIZE]) {
282 printf("SafeAlloc free: pointer %i is not inside pool and thus invalid!\n", int(p));
283 return;
284 }
285
286 SafeAlloc* const al = *a;
287
288 if(al < &safeAllocs[0] || al >= &safeAllocs[SAFEALLOC_MAXALLOCS]) {
289 printf("SafeAlloc free: pointer %i is messed up!\n", int(p));
290 return;
291 }
292
293 if(((size_t)al - (size_t)&safeAllocs[0]) % sizeof(SafeAlloc) != 0) {
294 printf("SafeAlloc free: pointer %i is fucked up!\n", int(p));
295 return;
296 }
297
298 if(!al->isUsed()) {
299 printf("SafeAlloc free: pointer %i is strange, perhaps already freed?!\n", int(p));
300 return;
301 }
302
303 if(safeAlloc_listEmpty()) {
304 printf("SafeAlloc free: pointer %i must be wrong, there aren't any allocations!\n", int(p));
305 return;
306 }
307
308 if(al->userPt() != p) {
309 printf("SafeAlloc free: pointer %i doesn't behave well!\n", int(p));
310 return;
311 }
312
313 if(al->left == NULL && safeAlloc_first != al) {
314 printf("SafeAlloc free: pointer %i is old!\n", int(p));
315 return;
316 }
317
318 if(al < safeAlloc_first) {
319 printf("SafeAlloc free: pointer %i is wrong, it must point to an old alloc!\n", int(p));
320 return;
321 }
322
323 if(al == safeAlloc_first && al->left != NULL) {
324 printf("SafeAlloc free: pointer %i has wrong linked list info!\n", int(p));
325 return;
326 }
327
328 // everything seems sane
329 // clean up now
330 //safeAlloc_dbg("free", al);
331 if(safeAlloc_lastAlloc == al)
332 safeAlloc_lastAlloc = al->left;
333 if(al->left == NULL) {
334 safeAlloc_first = al->right;
335 if(al->right) al->right->left = NULL;
336 } else {
337 al->left->right = al->right;
338 if(al->right) al->right->left = al->left;
339 }
340 al->reset();
341 }
342
343
344 template<typename _Tp>
345 class safe_allocator
346 {
347 public:
348 typedef size_t size_type;
349 typedef ptrdiff_t difference_type;
350 typedef _Tp* pointer;
351 typedef const _Tp* const_pointer;
352 typedef _Tp& reference;
353 typedef const _Tp& const_reference;
354 typedef _Tp value_type;
355
356 template<typename _Tp1>
357 struct rebind
358 { typedef safe_allocator<_Tp1> other; };
359
safe_allocator()360 safe_allocator() throw() { }
361
safe_allocator(const safe_allocator &)362 safe_allocator(const safe_allocator&) throw() { }
363
364 template<typename _Tp1>
safe_allocator(const safe_allocator<_Tp1> &)365 safe_allocator(const safe_allocator<_Tp1>&) throw() { }
366
~safe_allocator()367 ~safe_allocator() throw() { }
368
369 pointer
address(reference __x) const370 address(reference __x) const { return &__x; }
371
372 const_pointer
address(const_reference __x) const373 address(const_reference __x) const { return &__x; }
374
375 // NB: __n is permitted to be 0. The C++ standard says nothing
376 // about what the return value is when __n == 0.
377 pointer
allocate(size_type __n,const void * =0)378 allocate(size_type __n, const void* = 0)
379 {
380 pointer __ret = static_cast<_Tp*>(safeAlloc_alloc(__n * sizeof(_Tp)));
381 if (!__ret)
382 throw std::bad_alloc();
383 return __ret;
384 }
385
386 // __p is not permitted to be a null pointer.
387 void
deallocate(pointer __p,size_type)388 deallocate(pointer __p, size_type)
389 { safeAlloc_free(static_cast<void*>(__p)); }
390
391 size_type
max_size() const392 max_size() const throw()
393 { return SAFEALLOC_POOLSIZE - SafeAlloc::extraSpacePerAlloc; }
394
395 // _GLIBCXX_RESOLVE_LIB_DEFECTS
396 // 402. wrong new expression in [some_] allocator::construct
397 void
construct(pointer __p,const _Tp & __val)398 construct(pointer __p, const _Tp& __val)
399 { ::new(__p) value_type(__val); }
400
401 void
destroy(pointer __p)402 destroy(pointer __p) { __p->~_Tp(); }
403 };
404
405 template<typename _Tp>
406 inline bool
operator ==(const safe_allocator<_Tp> &,const safe_allocator<_Tp> &)407 operator==(const safe_allocator<_Tp>&, const safe_allocator<_Tp>&)
408 { return true; }
409
410 template<typename _Tp>
411 inline bool
operator !=(const safe_allocator<_Tp> &,const safe_allocator<_Tp> &)412 operator!=(const safe_allocator<_Tp>&, const safe_allocator<_Tp>&)
413 { return false; }
414
415
416 typedef std::basic_string<char, std::char_traits<char>, safe_allocator<char> > String;
417
dbgError(const String & err)418 static void dbgError(const String& err) {
419 printf("memstats error: %s\n", err.c_str());
420 RaiseDebugger();
421 DumpCallstackPrintf();
422 fflush(0);
423 }
424
dbgMsg(const String & msg)425 static void dbgMsg(const String& msg) {
426 printf("memstats: %s\n", msg.c_str());
427 fflush(0);
428 }
429
430 template<typename T>
IntToStr(T num,int base=10)431 String IntToStr(T num, int base = 10) {
432 String buf;
433 if(num < 0) { buf = "-"; num = -num; }
434
435 do {
436 buf = "0123456789abcdefghijklmnopqrstuvwxyz"[num % base] + buf;
437 num /= base;
438 } while(num);
439
440 return buf;
441 }
442
SizeAsStr(size_t sum)443 String SizeAsStr(size_t sum) {
444 if(sum < 2*1024)
445 return IntToStr(sum) + " B";
446 else if(sum < 2*1024*1024)
447 return IntToStr(sum / 1024) + " KB";
448 else
449 return IntToStr(sum / (1024*1024)) + " MB";
450 }
451
findLastPathSep(const String & path)452 size_t findLastPathSep(const String& path) {
453 size_t slash = path.rfind('\\');
454 size_t slash2 = path.rfind('/');
455 if(slash == String::npos)
456 slash = slash2;
457 else if(slash2 != String::npos)
458 slash = std::max(slash, slash2);
459 return slash;
460 }
461
GetBaseFilename(const String & filename)462 String GetBaseFilename(const String& filename) {
463 size_t p = findLastPathSep(filename);
464 if(p == String::npos) return filename;
465 return filename.substr(p+1);
466 }
467
468
469 typedef String FileName;
470 typedef int Line;
471 typedef std::pair<FileName,Line> ObjType;
472 typedef std::pair<ObjType,size_t> AllocInfo;
473
ObjTypeAsStr(const ObjType & obj)474 String ObjTypeAsStr(const ObjType& obj) {
475 return obj.first + ":" + IntToStr(obj.second);
476 }
477
AllocInfoAsStr(const AllocInfo & al)478 String AllocInfoAsStr(const AllocInfo& al) {
479 return ObjTypeAsStr(al.first) + "#" + IntToStr(al.second);
480 }
481
482 typedef std::map<ObjType, size_t, std::less<ObjType>, safe_allocator< std::pair<const ObjType, size_t> > > Allocations;
483 typedef std::map<void*, AllocInfo, std::less<void*>, safe_allocator< std::pair<void* const, AllocInfo> > > AllocInfoMap;
484
485 struct MemStats {
486 Mutex mutex;
487 Allocations allocSums;
488 AllocInfoMap allocInfos;
489 };
490 static MemStats* stats = NULL;
491 static bool finalCleanup = false;
492
initMemStats()493 static bool initMemStats() {
494 if(finalCleanup) return false;
495 if(stats == NULL) {
496 printf("--- MemStats initialisation ---\n");
497 safeAlloc_init();
498 stats = (MemStats*) malloc(sizeof(MemStats));
499 new(stats) MemStats;
500 }
501 return true;
502 }
503
504 struct MemStats_FinalCleanup {
~MemStats_FinalCleanupMemStats_FinalCleanup505 ~MemStats_FinalCleanup() {
506 if(stats != NULL) {
507 stats -> ~MemStats();
508 free(stats);
509 stats = NULL;
510 safeAlloc_uninit();
511 finalCleanup = true;
512 }
513 }
514 } memStats_finalCleanup;
515
516
operator new(size_t size,dmalloc_t,const char * file,int line)517 void * operator new (size_t size, dmalloc_t, const char* file, int line) {
518 void* p = malloc(size);
519
520 if(initMemStats()) {
521 ObjType obj( GetBaseFilename(String(file)), line );
522
523 if(p == NULL) {
524 dbgError("out-of-memory @" + ObjTypeAsStr(obj));
525 printMemStats();
526 throw std::bad_alloc();
527 }
528
529 Mutex::ScopedLock lock(stats->mutex);
530 stats->allocSums[obj] += size;
531 stats->allocInfos[p] = AllocInfo(obj, size);
532 }
533
534 return p;
535 }
536
operator new[](size_t size,dmalloc_t,const char * file,int line)537 void * operator new [] (size_t size, dmalloc_t, const char* file, int line) {
538 return :: operator new (size, dmalloc_t(), file, line);
539 }
540
operator new(size_t size)541 void * operator new (size_t size) throw (std::bad_alloc) {
542 return :: operator new (size, dmalloc_t(), "??", 0);
543 }
544
operator new[](size_t size)545 void * operator new [] (size_t size) throw (std::bad_alloc) {
546 return :: operator new (size, dmalloc_t(), "??", 0);
547 }
548
operator new(std::size_t size,const std::nothrow_t &)549 void* operator new(std::size_t size, const std::nothrow_t&) throw() {
550 try {
551 return :: operator new (size, dmalloc_t(), "??", 0);
552 }
553 catch(std::bad_alloc) {
554 return NULL;
555 }
556 }
557
operator new[](std::size_t size,const std::nothrow_t &)558 void* operator new[](std::size_t size, const std::nothrow_t&) throw() {
559 try {
560 return :: operator new (size, dmalloc_t(), "??", 0);
561 }
562 catch(std::bad_alloc) {
563 return NULL;
564 }
565 }
566
operator delete(void * p)567 void operator delete (void * p) throw() {
568 if(!initMemStats()) {
569 free(p);
570 return;
571 }
572
573 Mutex::ScopedLock lock(stats->mutex);
574
575 AllocInfoMap::iterator i = stats->allocInfos.find(p);
576 if(i == stats->allocInfos.end()) {
577 dbgError("deleting invalid pointer");
578 dbgMsg("* pointer: " + IntToStr((int)p));
579 if(stats->allocInfos.size() == 0) {
580 dbgMsg("* none allocations are made right now");
581 return;
582 }
583 i = stats->allocInfos.lower_bound(p);
584 if(i == stats->allocInfos.begin()) {
585 dbgMsg("* pointer is before first allocation");
586 dbgMsg("* first allocation @" + IntToStr((int)i->first));
587 return;
588 }
589 --i; // go before pointer
590 dbgMsg("* below alloc is " + AllocInfoAsStr(i->second) + " @" + IntToStr((int)i->first));
591 if((size_t)i->first + i->second.second > (size_t)p)
592 dbgMsg("* pointer IS inside that range");
593 else
594 dbgMsg("* pointer is NOT inside that range");
595 return;
596 }
597
598 const AllocInfo allocInfo = i->second;
599 stats->allocInfos.erase(i);
600 size_t& allocSum = stats->allocSums[allocInfo.first];
601 if(allocSum >= allocInfo.second)
602 allocSum -= allocInfo.second;
603 else {
604 dbgError("delete: allocation info messed up, allocSum too small");
605 dbgMsg("* pointer: " + IntToStr((int)p));
606 dbgMsg("* allocSum: " + IntToStr(allocSum));
607 dbgMsg("* alloc size: " + IntToStr(allocInfo.second));
608 allocSum = 0;
609 }
610
611 free(p);
612 }
613
operator delete[](void * p)614 void operator delete [] (void * p) throw() {
615 :: operator delete (p);
616 }
617
operator delete(void * p,const std::nothrow_t &)618 void operator delete(void* p, const std::nothrow_t&) throw() {
619 :: operator delete (p);
620 }
621
operator delete[](void * p,const std::nothrow_t &)622 void operator delete[](void* p , const std::nothrow_t&) throw() {
623 :: operator delete (p);
624 }
625
printMemStats()626 void printMemStats() {
627 if(stats) {
628 dbgMsg("-- MemStats --");
629
630 typedef std::multimap<size_t, ObjType, std::less<size_t>, safe_allocator< std::pair<const size_t,ObjType> > > Allocs;
631 Allocs allocs;
632 size_t sum = 0;
633 {
634 Mutex::ScopedLock lock(stats->mutex);
635 dbgMsg("allocs: " + IntToStr(stats->allocInfos.size()));
636 dbgMsg("num of different alloc types: " + IntToStr(stats->allocSums.size()));
637
638 // sort all alloc types by alloc sum
639 for(Allocations::iterator i = stats->allocSums.begin(); i != stats->allocSums.end(); ++i) {
640 allocs.insert( Allocs::value_type(i->second, i->first) );
641 sum += i->second;
642 }
643 }
644
645 dbgMsg("allocated mem: " + SizeAsStr(sum));
646 int count = 30;
647 for(Allocs::reverse_iterator i = allocs.rbegin(); i != allocs.rend(); ++i) {
648 dbgMsg(". " + ObjTypeAsStr(i->second) + " - " + SizeAsStr(i->first));
649 count--;
650 if(count <= 0) break;
651 }
652 dbgMsg(".");
653 }
654 else
655 // NOTE: we cannot use dbgMsg because this needs the safeAlloc system which is init together with memstats
656 printf("* MemStats not initialised *\n");
657 }
658
659
660 #endif
661
662