Logo ROOT   6.08/07
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 
88 ////////////////////////////////////////////////////////////////////////////////
89 /// Register a memory allocation operation. If desired one can trap an
90 /// allocation of a certain size in case one tries to find a memory
91 /// leak of that particular size. This function is only called via
92 /// the ROOT custom new operators.
93 
94 void TStorage::EnterStat(size_t size, void *p)
95 {
97 
98  if (!gMemStatistics) return;
99 
100  if ((Int_t)size == gMemSize) {
101  if (gTraceIndex == gMemIndex)
102  Fatal("EnterStat", "trapped allocation %d", gMemIndex);
103 
104  if (!gTraceArray)
105  gTraceArray = (void**) malloc(sizeof(void*)*gTraceCapacity);
106 
107  if (gTraceIndex >= gTraceCapacity) {
108  gTraceCapacity = gTraceCapacity*2;
109  gTraceArray = (void**) realloc(gTraceArray, sizeof(void*)*gTraceCapacity);
110  }
111  gTraceArray[gTraceIndex++] = p;
112  }
113  if (size >= kObjMaxSize)
114  gAllocated[kObjMaxSize-1]++;
115  else
116  gAllocated[size]++;
117  gAllocatedTotal += size;
118 }
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 /// Register a memory free operation. This function is only called via
122 /// the custom ROOT delete operator.
123 
124 void TStorage::RemoveStat(void *vp)
125 {
126  if (!gMemStatistics) return;
127 
128  size_t size = storage_size(vp);
129  if ((Int_t)size == gMemSize) {
130  for (int i = 0; i < gTraceIndex; i++)
131  if (gTraceArray[i] == vp) {
132  gTraceArray[i] = 0;
133  break;
134  }
135  }
136  if (size >= kObjMaxSize)
137  gFreed[kObjMaxSize-1]++;
138  else
139  gFreed[size]++;
140  gFreedTotal += size;
141 }
142 
143 ////////////////////////////////////////////////////////////////////////////////
144 /// Allocate a block of memory, that later can be resized using
145 /// TStorage::ReAlloc().
146 
147 void *TStorage::Alloc(size_t size)
148 {
149  static const char *where = "TStorage::Alloc";
150 
151 #ifndef WIN32
152  void *vp = ::operator new[](size);
153 #else
154  void *vp = ::operator new(size);
155 #endif
156  if (vp == 0)
157  Fatal(where, "%s", gSpaceErr);
158 
159  return vp;
160 }
161 
162 ////////////////////////////////////////////////////////////////////////////////
163 /// De-allocate block of memory, that was allocated via TStorage::Alloc().
164 
165 void TStorage::Dealloc(void *ptr)
166 {
167 #ifndef WIN32
168  ::operator delete[](ptr);
169 #else
170  ::operator delete(ptr);
171 #endif
172 }
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 /// Reallocate (i.e. resize) block of memory. Don't use if size is larger
176 /// than old size, use ReAlloc(void *, size_t, size_t) instead.
177 
178 void *TStorage::ReAlloc(void *ovp, size_t size)
179 {
180  ::Obsolete("ReAlloc(void*,size_t)", "v5-34-00", "v6-02-00");
181  ::Info("ReAlloc(void*,size_t)", "please use ReAlloc(void*,size_t,size_t)");
182 
183  {
184  // Needs to be protected by global mutex
186 
188  return (*fgReAllocHook)(ovp, size);
189  }
190 
191  static const char *where = "TStorage::ReAlloc";
192 
193 #ifndef WIN32
194  void *vp = ::operator new[](size);
195 #else
196  void *vp = ::operator new(size);
197 #endif
198  if (vp == 0)
199  Fatal(where, "%s", gSpaceErr);
200 
201  if (ovp == 0)
202  return vp;
203 
204  memmove(vp, ovp, size);
205 #ifndef WIN32
206  ::operator delete[](ovp);
207 #else
208  ::operator delete(ovp);
209 #endif
210  return vp;
211 }
212 
213 ////////////////////////////////////////////////////////////////////////////////
214 /// Reallocate (i.e. resize) block of memory. Checks if current size is
215 /// equal to oldsize. If not memory was overwritten.
216 
217 void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
218 {
219  // Needs to be protected by global mutex
220  {
222 
224  return (*fgReAllocCHook)(ovp, size, oldsize);
225  }
226 
227  static const char *where = "TStorage::ReAlloc";
228 
229  if (oldsize == size)
230  return ovp;
231 
232 #ifndef WIN32
233  void *vp = ::operator new[](size);
234 #else
235  void *vp = ::operator new(size);
236 #endif
237  if (vp == 0)
238  Fatal(where, "%s", gSpaceErr);
239 
240  if (ovp == 0)
241  return vp;
242 
243  if (size > oldsize) {
244  memcpy(vp, ovp, oldsize);
245  memset((char*)vp+oldsize, 0, size-oldsize);
246  } else
247  memcpy(vp, ovp, size);
248 #ifndef WIN32
249  ::operator delete[](ovp);
250 #else
251  ::operator delete(ovp);
252 #endif
253  return vp;
254 }
255 
256 ////////////////////////////////////////////////////////////////////////////////
257 /// Reallocate (i.e. resize) array of chars. Size and oldsize are
258 /// in number of chars.
259 
260 char *TStorage::ReAllocChar(char *ovp, size_t size, size_t oldsize)
261 {
262  static const char *where = "TStorage::ReAllocChar";
263 
264  char *vp;
265  if (ovp == 0) {
266  vp = new char[size];
267  if (vp == 0)
268  Fatal(where, "%s", gSpaceErr);
269  return vp;
270  }
271  if (oldsize == size)
272  return ovp;
273 
274  vp = new char[size];
275  if (vp == 0)
276  Fatal(where, "%s", gSpaceErr);
277  if (size > oldsize) {
278  memcpy(vp, ovp, oldsize);
279  memset((char*)vp+oldsize, 0, size-oldsize);
280  } else
281  memcpy(vp, ovp, size);
282  delete [] ovp;
283  return vp;
284 }
285 
286 ////////////////////////////////////////////////////////////////////////////////
287 /// Reallocate (i.e. resize) array of integers. Size and oldsize are
288 /// number of integers (not number of bytes).
289 
290 Int_t *TStorage::ReAllocInt(Int_t *ovp, size_t size, size_t oldsize)
291 {
292  static const char *where = "TStorage::ReAllocInt";
293 
294  Int_t *vp;
295  if (ovp == 0) {
296  vp = new Int_t[size];
297  if (vp == 0)
298  Fatal(where, "%s", gSpaceErr);
299  return vp;
300  }
301  if (oldsize == size)
302  return ovp;
303 
304  vp = new Int_t[size];
305  if (vp == 0)
306  Fatal(where, "%s", gSpaceErr);
307  if (size > oldsize) {
308  memcpy(vp, ovp, oldsize*sizeof(Int_t));
309  memset((Int_t*)vp+oldsize, 0, (size-oldsize)*sizeof(Int_t));
310  } else
311  memcpy(vp, ovp, size*sizeof(Int_t));
312  delete [] ovp;
313  return vp;
314 }
315 
316 ////////////////////////////////////////////////////////////////////////////////
317 /// Used to allocate a TObject on the heap (via TObject::operator new()).
318 /// Directly after this routine one can call (in the TObject ctor)
319 /// TStorage::FilledByObjectAlloc() to find out if the just created object is on
320 /// the heap. This technique is necessary as there is one stack per thread
321 /// and we can not rely on comparison with the current stack memory position.
322 
323 void *TStorage::ObjectAlloc(size_t sz)
324 {
325  void* space = ::operator new(sz);
326  memset(space, kObjectAllocMemValue, sz);
327  return space;
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 /// Used to allocate array of TObject on the heap (via TObject::operator new[]()).
332 /// Unlike the 'singular' ObjectAlloc, we do not mark those object has being
333 /// allocated on the heap as they can not be individually deleted.
334 
336 {
337  void* space = ::operator new(sz);
338  return space;
339 }
340 
341 ////////////////////////////////////////////////////////////////////////////////
342 /// Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
343 /// in position vp. vp is already allocated (maybe on heap, maybe on
344 /// stack) so just return.
345 
346 void *TStorage::ObjectAlloc(size_t , void *vp)
347 {
348  return vp;
349 }
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 /// Used to deallocate a TObject on the heap (via TObject::operator delete()).
353 
355 {
356 
357  ::operator delete(vp);
358 }
359 
360 ////////////////////////////////////////////////////////////////////////////////
361 /// Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).
362 
363 void TStorage::ObjectDealloc(void *vp, void *ptr)
364 {
365  if (vp && ptr) { }
366 }
367 
368 #ifdef R__SIZEDDELETE
369 ////////////////////////////////////////////////////////////////////////////////
370 /// Used to deallocate a TObject on the heap (via TObject::operator delete()),
371 /// for sized deallocation.
372 
373 void TStorage::ObjectDealloc(void *vp, size_t size)
374 {
375 #if !defined(R__MACOSX) || !defined(MAC_OS_X_VERSION_10_12)
376  (void)size;
377  ::operator delete(vp);
378 #else
379  ::operator delete(vp, size);
380 #endif
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 ///called by TObject's constructor to determine if object was created by call to new
524 
526 {
527  // This technique is necessary as there is one stack per thread
528  // and we can not rely on comparison with the current stack memory position.
529  // Note that a false positive (this routine returning true for an object
530  // created on the stack) requires the previous stack value to have been
531  // set to exactly kObjectAllocMemValue at exactly the right position (i.e.
532  // where this object's fUniqueID is located.
533  // The consequence of a false positive will be visible if and only if
534  // the object is auto-added to a TDirectory (i.e. TTree, TH*, TGraph,
535  // TEventList) or explicitly added to the directory by the user
536  // and
537  // the TDirectory (or TFile) object is created on the stack *before*
538  // the object.
539  // The consequence would be that those objects would be deleted twice, once
540  // by the TDirectory and once automatically when going out of scope
541  // (and thus quite visible). A false negative (which is not posible with
542  // this implementation) would have been a silent memory leak.
543 
544  // This will be reported by valgrind as uninitialized memory reads for
545  // object created on the stack, use $ROOTSYS/etc/valgrind-root.supp
546  return *member == kObjectAllocMemValue;
547 }
548 
549 ////////////////////////////////////////////////////////////////////////////////
550 ///return max block size
551 
553 {
554  return fgMaxBlockSize;
555 }
556 
557 ////////////////////////////////////////////////////////////////////////////////
558 ///set max block size
559 
560 void TStorage::SetMaxBlockSize(size_t size)
561 {
562  fgMaxBlockSize = size;
563 }
564 
565 ////////////////////////////////////////////////////////////////////////////////
566 ///return free hook
567 
569 {
570  return fgFreeHook;
571 }
572 
573 #endif
static void Dealloc(void *ptr)
De-allocate block of memory, that was allocated via TStorage::Alloc().
Definition: TStorage.cxx:165
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
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:2634
static void * ObjectAlloc(size_t size)
Used to allocate a TObject on the heap (via TObject::operator new()).
Definition: TStorage.cxx:323
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:260
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:114
R__EXTERN TVirtualMutex * gGlobalMutex
Definition: TVirtualMutex.h:29
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:118
#define storage_size(p)
Definition: TStorage.cxx:56
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: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
static void * Alloc(size_t size)
Allocate a block of memory, that later can be resized using TStorage::ReAlloc().
Definition: TStorage.cxx:147
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:279
static Bool_t IsOnHeap(void *p)
is object at p in the heap?
Definition: TStorage.cxx:515
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:178
void(* FreeHookFun_t)(void *, void *addr, size_t)
Definition: TStorage.h:27
typedef void((*Func_t)())
static void RemoveStat(void *p)
Register a memory free operation.
Definition: TStorage.cxx:124
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:202
static void SetMaxBlockSize(size_t size)
Definition: TStorage.h:116
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:335
static Bool_t FilledByObjectAlloc(UInt_t *member)
Definition: TStorage.h:89
static void ** gTraceArray
Definition: TStorage.cxx:83
const Bool_t kTRUE
Definition: Rtypes.h:91
static ReAllocFun_t fgReAllocHook
Definition: TStorage.h:39
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:354
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:290