Logo ROOT   6.10/09
Reference Guide
TStorage.cxx
Go to the documentation of this file.
1 // @(#)root/base:$Id$
2 // Author: Fons Rademakers 29/07/95
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TStorage
13 \ingroup Base
14 
15 Storage manager. The storage manager works best in conjunction with
16 the custom ROOT new and delete operators defined in the file
17 NewDelete.cxx (libNew.so). Only when using the custom allocation
18 operators will memory usage statistics be gathered using the
19 TStorage EnterStat(), RemoveStat(), etc. functions.
20 Memory checking is by default enabled (when using libNew.so) and
21 usage statistics is gathered. Using the resource (in .rootrc):
22 Root.MemStat one can toggle statistics gathering on or off. More
23 specifically on can trap the allocation of a block of memory of a
24 certain size. This can be specified using the resource:
25 Root.MemStat.size, using the resource Root.MemStat.cnt one can
26 specify after how many allocations of this size the trap should
27 occur.
28 
29 Set the compile option R__NOSTATS to de-activate all memory checking
30 and statistics gathering in the system.
31 */
32 
33 #include <stdlib.h>
34 
35 #include "TROOT.h"
36 #include "TObjectTable.h"
37 #include "TError.h"
38 #include "TString.h"
39 #include "TVirtualMutex.h"
40 #include "TInterpreter.h"
41 
42 #if !defined(R__NOSTATS)
43 # define MEM_DEBUG
44 # define MEM_STAT
45 # define MEM_CHECKOBJECTPOINTERS
46 #endif
47 
48 #if defined(MEM_STAT) && !defined(MEM_DEBUG)
49 # define MEM_DEBUG
50 #endif
51 
52 #ifdef MEM_DEBUG
53 # ifdef R__B64
54 # define storage_size(p) ((size_t)(((size_t*)p)[-1]))
55 # else
56 # define storage_size(p) ((size_t)(((int*)p)[-2]))
57 # endif
58 #else
59 # define storage_size(p) ((size_t)0)
60 #endif
61 
62 #define PVOID (-1)
63 
70 
71 
73 
74 //------------------------------------------------------------------------------
75 
76 static const char *gSpaceErr = "storage exhausted";
77 
78 const size_t kObjMaxSize = 10024;
79 
81 static Int_t gAllocated[kObjMaxSize], gFreed[kObjMaxSize];
83 static void **gTraceArray = 0;
84 static Int_t gTraceCapacity = 10, gTraceIndex = 0,
85  gMemSize = -1, gMemIndex = -1;
86 
87 // Used in NewDelete.cxx; set by TMapFile.
88 ROOT::Internal::FreeIfTMapFile_t *ROOT::Internal::gFreeIfTMapFile = nullptr;
89 void *ROOT::Internal::gMmallocDesc = 0; //is used and set in TMapFile
90 
91 
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 /// Register a memory allocation operation. If desired one can trap an
95 /// allocation of a certain size in case one tries to find a memory
96 /// leak of that particular size. This function is only called via
97 /// the ROOT custom new operators.
98 
99 void TStorage::EnterStat(size_t size, void *p)
100 {
102 
103  if (!gMemStatistics) return;
104 
105  if ((Int_t)size == gMemSize) {
106  if (gTraceIndex == gMemIndex)
107  Fatal("EnterStat", "trapped allocation %d", gMemIndex);
108 
109  if (!gTraceArray)
110  gTraceArray = (void**) malloc(sizeof(void*)*gTraceCapacity);
111 
112  if (gTraceIndex >= gTraceCapacity) {
113  gTraceCapacity = gTraceCapacity*2;
114  gTraceArray = (void**) realloc(gTraceArray, sizeof(void*)*gTraceCapacity);
115  }
116  gTraceArray[gTraceIndex++] = p;
117  }
118  if (size >= kObjMaxSize)
119  gAllocated[kObjMaxSize-1]++;
120  else
121  gAllocated[size]++;
122  gAllocatedTotal += size;
123 }
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// Register a memory free operation. This function is only called via
127 /// the custom ROOT delete operator.
128 
129 void TStorage::RemoveStat(void *vp)
130 {
131  if (!gMemStatistics) return;
132 
133  size_t size = storage_size(vp);
134  if ((Int_t)size == gMemSize) {
135  for (int i = 0; i < gTraceIndex; i++)
136  if (gTraceArray[i] == vp) {
137  gTraceArray[i] = 0;
138  break;
139  }
140  }
141  if (size >= kObjMaxSize)
142  gFreed[kObjMaxSize-1]++;
143  else
144  gFreed[size]++;
145  gFreedTotal += size;
146 }
147 
148 ////////////////////////////////////////////////////////////////////////////////
149 /// Allocate a block of memory, that later can be resized using
150 /// TStorage::ReAlloc().
151 
152 void *TStorage::Alloc(size_t size)
153 {
154  static const char *where = "TStorage::Alloc";
155 
156 #ifndef WIN32
157  void *vp = ::operator new[](size);
158 #else
159  void *vp = ::operator new(size);
160 #endif
161  if (vp == 0)
162  Fatal(where, "%s", gSpaceErr);
163 
164  return vp;
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// De-allocate block of memory, that was allocated via TStorage::Alloc().
169 
170 void TStorage::Dealloc(void *ptr)
171 {
172 #ifndef WIN32
173  ::operator delete[](ptr);
174 #else
175  ::operator delete(ptr);
176 #endif
177 }
178 
179 ////////////////////////////////////////////////////////////////////////////////
180 /// Reallocate (i.e. resize) block of memory. Don't use if size is larger
181 /// than old size, use ReAlloc(void *, size_t, size_t) instead.
182 
183 void *TStorage::ReAlloc(void *ovp, size_t size)
184 {
185  ::Obsolete("ReAlloc(void*,size_t)", "v5-34-00", "v6-02-00");
186  ::Info("ReAlloc(void*,size_t)", "please use ReAlloc(void*,size_t,size_t)");
187 
188  {
189  // Needs to be protected by global mutex
191 
193  return (*fgReAllocHook)(ovp, size);
194  }
195 
196  static const char *where = "TStorage::ReAlloc";
197 
198 #ifndef WIN32
199  void *vp = ::operator new[](size);
200 #else
201  void *vp = ::operator new(size);
202 #endif
203  if (vp == 0)
204  Fatal(where, "%s", gSpaceErr);
205 
206  if (ovp == 0)
207  return vp;
208 
209  memmove(vp, ovp, size);
210 #ifndef WIN32
211  ::operator delete[](ovp);
212 #else
213  ::operator delete(ovp);
214 #endif
215  return vp;
216 }
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 /// Reallocate (i.e. resize) block of memory. Checks if current size is
220 /// equal to oldsize. If not memory was overwritten.
221 
222 void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
223 {
224  // Needs to be protected by global mutex
225  {
227 
229  return (*fgReAllocCHook)(ovp, size, oldsize);
230  }
231 
232  static const char *where = "TStorage::ReAlloc";
233 
234  if (oldsize == size)
235  return ovp;
236 
237 #ifndef WIN32
238  void *vp = ::operator new[](size);
239 #else
240  void *vp = ::operator new(size);
241 #endif
242  if (vp == 0)
243  Fatal(where, "%s", gSpaceErr);
244 
245  if (ovp == 0)
246  return vp;
247 
248  if (size > oldsize) {
249  memcpy(vp, ovp, oldsize);
250  memset((char*)vp+oldsize, 0, size-oldsize);
251  } else
252  memcpy(vp, ovp, size);
253 #ifndef WIN32
254  ::operator delete[](ovp);
255 #else
256  ::operator delete(ovp);
257 #endif
258  return vp;
259 }
260 
261 ////////////////////////////////////////////////////////////////////////////////
262 /// Reallocate (i.e. resize) array of chars. Size and oldsize are
263 /// in number of chars.
264 
265 char *TStorage::ReAllocChar(char *ovp, size_t size, size_t oldsize)
266 {
267  static const char *where = "TStorage::ReAllocChar";
268 
269  char *vp;
270  if (ovp == 0) {
271  vp = new char[size];
272  if (vp == 0)
273  Fatal(where, "%s", gSpaceErr);
274  return vp;
275  }
276  if (oldsize == size)
277  return ovp;
278 
279  vp = new char[size];
280  if (vp == 0)
281  Fatal(where, "%s", gSpaceErr);
282  if (size > oldsize) {
283  memcpy(vp, ovp, oldsize);
284  memset((char*)vp+oldsize, 0, size-oldsize);
285  } else
286  memcpy(vp, ovp, size);
287  delete [] ovp;
288  return vp;
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 /// Reallocate (i.e. resize) array of integers. Size and oldsize are
293 /// number of integers (not number of bytes).
294 
295 Int_t *TStorage::ReAllocInt(Int_t *ovp, size_t size, size_t oldsize)
296 {
297  static const char *where = "TStorage::ReAllocInt";
298 
299  Int_t *vp;
300  if (ovp == 0) {
301  vp = new Int_t[size];
302  if (vp == 0)
303  Fatal(where, "%s", gSpaceErr);
304  return vp;
305  }
306  if (oldsize == size)
307  return ovp;
308 
309  vp = new Int_t[size];
310  if (vp == 0)
311  Fatal(where, "%s", gSpaceErr);
312  if (size > oldsize) {
313  memcpy(vp, ovp, oldsize*sizeof(Int_t));
314  memset((Int_t*)vp+oldsize, 0, (size-oldsize)*sizeof(Int_t));
315  } else
316  memcpy(vp, ovp, size*sizeof(Int_t));
317  delete [] ovp;
318  return vp;
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Used to allocate a TObject on the heap (via TObject::operator new()).
323 /// Directly after this routine one can call (in the TObject ctor)
324 /// TStorage::FilledByObjectAlloc() to find out if the just created object is on
325 /// the heap. This technique is necessary as there is one stack per thread
326 /// and we can not rely on comparison with the current stack memory position.
327 
328 void *TStorage::ObjectAlloc(size_t sz)
329 {
330  void* space = ::operator new(sz);
331  memset(space, kObjectAllocMemValue, sz);
332  return space;
333 }
334 
335 ////////////////////////////////////////////////////////////////////////////////
336 /// Used to allocate array of TObject on the heap (via TObject::operator new[]()).
337 /// Unlike the 'singular' ObjectAlloc, we do not mark those object has being
338 /// allocated on the heap as they can not be individually deleted.
339 
341 {
342  void* space = ::operator new(sz);
343  return space;
344 }
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 /// Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
348 /// in position vp. vp is already allocated (maybe on heap, maybe on
349 /// stack) so just return.
350 
351 void *TStorage::ObjectAlloc(size_t , void *vp)
352 {
353  return vp;
354 }
355 
356 ////////////////////////////////////////////////////////////////////////////////
357 /// Used to deallocate a TObject on the heap (via TObject::operator delete()).
358 
360 {
361 
362  ::operator delete(vp);
363 }
364 
365 ////////////////////////////////////////////////////////////////////////////////
366 /// Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).
367 
368 void TStorage::ObjectDealloc(void *vp, void *ptr)
369 {
370  if (vp && ptr) { }
371 }
372 
373 #ifdef R__SIZEDDELETE
374 ////////////////////////////////////////////////////////////////////////////////
375 /// Used to deallocate a TObject on the heap (via TObject::operator delete()),
376 /// for sized deallocation.
377 
378 void TStorage::ObjectDealloc(void *vp, size_t size)
379 {
380  ::operator delete(vp, size);
381 }
382 #endif
383 
384 ////////////////////////////////////////////////////////////////////////////////
385 /// Set a free handler.
386 
388 {
389  fgFreeHook = fh;
391 }
392 
393 ////////////////////////////////////////////////////////////////////////////////
394 /// Set a custom ReAlloc handlers. This function is typically
395 /// called via a static object in the ROOT libNew.so shared library.
396 
398 {
399  fgReAllocHook = rh1;
400  fgReAllocCHook = rh2;
401 }
402 
403 ////////////////////////////////////////////////////////////////////////////////
404 /// Print memory usage statistics.
405 
407 {
408  // Needs to be protected by global mutex
410 
411 #if defined(MEM_DEBUG) && defined(MEM_STAT)
412 
414  return;
415 
416  //Printf("");
417  Printf("Heap statistics");
418  Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
419  Printf("================================================");
420 
421  int i;
422  for (i = 0; i < (int)kObjMaxSize; i++)
423  if (gAllocated[i] != gFreed[i])
424  //if (gAllocated[i])
425  Printf("%12d%12d%12d%12d", i, gAllocated[i], gFreed[i],
426  gAllocated[i]-gFreed[i]);
427 
428  if (gAllocatedTotal != gFreedTotal) {
429  Printf("------------------------------------------------");
430  Printf("Total: %12d%12d%12d", gAllocatedTotal, gFreedTotal,
432  }
433 
434  if (gMemSize != -1) {
435  Printf("------------------------------------------------");
436  for (i= 0; i < gTraceIndex; i++)
437  if (gTraceArray[i])
438  Printf("block %d of size %d not freed", i, gMemSize);
439  }
440  Printf("================================================");
441  Printf(" ");
442 #endif
443 }
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 /// Enable memory usage statistics gathering. Size is the size of the memory
447 /// block that should be trapped and ix is after how many such allocations
448 /// the trap should happen.
449 
450 void TStorage::EnableStatistics(int size, int ix)
451 {
452 #ifdef MEM_STAT
453  gMemSize = size;
454  gMemIndex = ix;
456 #else
457  int idum = size; int iidum = ix;
458 #endif
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 
464 {
465  ::Obsolete("GetHeapBegin()", "v5-34-00", "v6-02-00");
466  //return begin of heap
467  return 0;
468 }
469 
470 ////////////////////////////////////////////////////////////////////////////////
471 
473 {
474  ::Obsolete("GetHeapBegin()", "v5-34-00", "v6-02-00");
475  //return end of heap
476  return 0;
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 ///return static free hook data
481 
483 {
484  return fgFreeHookData;
485 }
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 ///return the has custom delete flag
489 
491 {
492  return fgHasCustomNewDelete;
493 }
494 
495 ////////////////////////////////////////////////////////////////////////////////
496 ///set the has custom delete flag
497 
499 {
501 }
502 
503 
504 ////////////////////////////////////////////////////////////////////////////////
505 ///add a range to the heap
506 
508 {
509  ::Obsolete("AddToHeap(ULong_t,ULong_t)", "v5-34-00", "v6-02-00");
510 }
511 
512 ////////////////////////////////////////////////////////////////////////////////
513 ///is object at p in the heap?
514 
516 {
517  ::Obsolete("IsOnHeap(void*)", "v5-34-00", "v6-02-00");
518  return false;
519 }
520 
521 #ifdef WIN32
522 ////////////////////////////////////////////////////////////////////////////////
523 ///return max block size
524 
526 {
527  return fgMaxBlockSize;
528 }
529 
530 ////////////////////////////////////////////////////////////////////////////////
531 ///set max block size
532 
533 void TStorage::SetMaxBlockSize(size_t size)
534 {
535  fgMaxBlockSize = size;
536 }
537 
538 ////////////////////////////////////////////////////////////////////////////////
539 ///return free hook
540 
542 {
543  return fgFreeHook;
544 }
545 
546 #endif
static void Dealloc(void *ptr)
De-allocate block of memory, that was allocated via TStorage::Alloc().
Definition: TStorage.cxx:170
void *(* ReAllocFun_t)(void *, size_t)
Definition: TStorage.h:28
static Int_t gTraceIndex
Definition: TStorage.cxx:84
static Int_t gMemSize
Definition: TStorage.cxx:85
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
void Fatal(const char *location, const char *msgfmt,...)
static const UInt_t kObjectAllocMemValue
Definition: TStorage.h:42
static ULong_t GetHeapBegin()
Definition: TStorage.cxx:463
static Bool_t MemCheck()
Return kTRUE if the memory leak checker is on.
Definition: TROOT.cxx:2648
static void * ObjectAlloc(size_t size)
Used to allocate a TObject on the heap (via TObject::operator new()).
Definition: TStorage.cxx:328
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
static const char * gSpaceErr
Definition: TStorage.cxx:76
static ULong_t GetHeapEnd()
Definition: TStorage.cxx:472
#define malloc
Definition: civetweb.c:818
void Obsolete(const char *function, const char *asOfVers, const char *removedFromVers)
Use this function to declare a function obsolete.
Definition: TError.cxx:278
static ReAllocCFun_t fgReAllocCHook
Definition: TStorage.h:40
static void AddToHeap(ULong_t begin, ULong_t end)
add a range to the heap
Definition: TStorage.cxx:507
static char * ReAllocChar(char *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition: TStorage.cxx:265
R__EXTERN void * gMmallocDesc
Definition: TStorage.h:126
static void * fgFreeHookData
Definition: TStorage.h:38
void Info(const char *location, const char *msgfmt,...)
static Int_t gFreedTotal
Definition: TStorage.cxx:82
#define realloc
Definition: civetweb.c:820
static Bool_t fgHasCustomNewDelete
Definition: TStorage.h:41
static size_t GetMaxBlockSize()
Definition: TStorage.h:116
R__EXTERN TVirtualMutex * gGlobalMutex
Definition: TVirtualMutex.h:27
static Int_t gMemIndex
Definition: TStorage.cxx:85
static Bool_t gMemStatistics
Definition: TStorage.cxx:80
static void * GetFreeHookData()
return static free hook data
Definition: TStorage.cxx:482
static FreeHookFun_t GetFreeHook()
Definition: TStorage.h:120
#define storage_size(p)
Definition: TStorage.cxx:56
static void EnableStatistics(int size=-1, int ix=-1)
Enable memory usage statistics gathering.
Definition: TStorage.cxx:450
static Bool_t HasCustomNewDelete()
return the has custom delete flag
Definition: TStorage.cxx:490
static void SetCustomNewDelete()
set the has custom delete flag
Definition: TStorage.cxx:498
static Int_t gAllocatedTotal
Definition: TStorage.cxx:82
static FreeHookFun_t fgFreeHook
Definition: TStorage.h:37
static void SetReAllocHooks(ReAllocFun_t func1, ReAllocCFun_t func2)
Set a custom ReAlloc handlers.
Definition: TStorage.cxx:397
#define Printf
Definition: TGeoToOCC.h:18
bool(void *) FreeIfTMapFile_t
Definition: TStorage.h:124
static void * Alloc(size_t size)
Allocate a block of memory, that later can be resized using TStorage::ReAlloc().
Definition: TStorage.cxx:152
static Int_t gAllocated[kObjMaxSize]
Definition: TStorage.cxx:81
static void SetFreeHook(FreeHookFun_t func, void *data)
Set a free handler.
Definition: TStorage.cxx:387
#define ClassImp(name)
Definition: Rtypes.h:336
static Bool_t IsOnHeap(void *p)
is object at p in the heap?
Definition: TStorage.cxx:515
R__EXTERN FreeIfTMapFile_t * gFreeIfTMapFile
Definition: TStorage.h:125
unsigned long ULong_t
Definition: RtypesCore.h:51
void *(* ReAllocCFun_t)(void *, size_t, size_t)
Definition: TStorage.h:29
#define R__LOCKGUARD(mutex)
static Int_t gFreed[kObjMaxSize]
Definition: TStorage.cxx:81
static void * ReAlloc(void *vp, size_t size)
Reallocate (i.e.
Definition: TStorage.cxx:183
void(* FreeHookFun_t)(void *, void *addr, size_t)
Definition: TStorage.h:27
static void RemoveStat(void *p)
Register a memory free operation.
Definition: TStorage.cxx:129
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
static void SetMaxBlockSize(size_t size)
Definition: TStorage.h:118
static Int_t gTraceCapacity
Definition: TStorage.cxx:84
const size_t kObjMaxSize
Definition: TStorage.cxx:78
static void * ObjectAllocArray(size_t size)
Used to allocate array of TObject on the heap (via TObject::operator new[]()).
Definition: TStorage.cxx:340
static void ** gTraceArray
Definition: TStorage.cxx:83
static ReAllocFun_t fgReAllocHook
Definition: TStorage.h:39
const Bool_t kTRUE
Definition: RtypesCore.h:91
static size_t fgMaxBlockSize
Definition: TStorage.h:36
static void ObjectDealloc(void *vp)
Used to deallocate a TObject on the heap (via TObject::operator delete()).
Definition: TStorage.cxx:359
static void PrintStatistics()
Print memory usage statistics.
Definition: TStorage.cxx:406
Storage manager.
Definition: TStorage.h:33
static Int_t * ReAllocInt(Int_t *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition: TStorage.cxx:295