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