Logo ROOT   6.07/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 
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 ////////////////////////////////////////////////////////////////////////////////
369 /// Set a free handler.
370 
372 {
373  fgFreeHook = fh;
374  fgFreeHookData = data;
375 }
376 
377 ////////////////////////////////////////////////////////////////////////////////
378 /// Set a custom ReAlloc handlers. This function is typically
379 /// called via a static object in the ROOT libNew.so shared library.
380 
382 {
383  fgReAllocHook = rh1;
384  fgReAllocCHook = rh2;
385 }
386 
387 ////////////////////////////////////////////////////////////////////////////////
388 /// Print memory usage statistics.
389 
391 {
392  // Needs to be protected by global mutex
394 
395 #if defined(MEM_DEBUG) && defined(MEM_STAT)
396 
398  return;
399 
400  //Printf("");
401  Printf("Heap statistics");
402  Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
403  Printf("================================================");
404 
405  int i;
406  for (i = 0; i < (int)kObjMaxSize; i++)
407  if (gAllocated[i] != gFreed[i])
408  //if (gAllocated[i])
409  Printf("%12d%12d%12d%12d", i, gAllocated[i], gFreed[i],
410  gAllocated[i]-gFreed[i]);
411 
412  if (gAllocatedTotal != gFreedTotal) {
413  Printf("------------------------------------------------");
414  Printf("Total: %12d%12d%12d", gAllocatedTotal, gFreedTotal,
416  }
417 
418  if (gMemSize != -1) {
419  Printf("------------------------------------------------");
420  for (i= 0; i < gTraceIndex; i++)
421  if (gTraceArray[i])
422  Printf("block %d of size %d not freed", i, gMemSize);
423  }
424  Printf("================================================");
425  Printf(" ");
426 #endif
427 }
428 
429 ////////////////////////////////////////////////////////////////////////////////
430 /// Enable memory usage statistics gathering. Size is the size of the memory
431 /// block that should be trapped and ix is after how many such allocations
432 /// the trap should happen.
433 
434 void TStorage::EnableStatistics(int size, int ix)
435 {
436 #ifdef MEM_STAT
437  gMemSize = size;
438  gMemIndex = ix;
440 #else
441  int idum = size; int iidum = ix;
442 #endif
443 }
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 
448 {
449  ::Obsolete("GetHeapBegin()", "v5-34-00", "v6-02-00");
450  //return begin of heap
451  return 0;
452 }
453 
454 ////////////////////////////////////////////////////////////////////////////////
455 
457 {
458  ::Obsolete("GetHeapBegin()", "v5-34-00", "v6-02-00");
459  //return end of heap
460  return 0;
461 }
462 
463 ////////////////////////////////////////////////////////////////////////////////
464 ///return static free hook data
465 
467 {
468  return fgFreeHookData;
469 }
470 
471 ////////////////////////////////////////////////////////////////////////////////
472 ///return the has custom delete flag
473 
475 {
476  return fgHasCustomNewDelete;
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 ///set the has custom delete flag
481 
483 {
485 }
486 
487 
488 ////////////////////////////////////////////////////////////////////////////////
489 ///add a range to the heap
490 
492 {
493  ::Obsolete("AddToHeap(ULong_t,ULong_t)", "v5-34-00", "v6-02-00");
494 }
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 ///is object at p in the heap?
498 
500 {
501  ::Obsolete("IsOnHeap(void*)", "v5-34-00", "v6-02-00");
502  return false;
503 }
504 
505 #ifdef WIN32
506 ////////////////////////////////////////////////////////////////////////////////
507 ///called by TObject's constructor to determine if object was created by call to new
508 
510 {
511  // This technique is necessary as there is one stack per thread
512  // and we can not rely on comparison with the current stack memory position.
513  // Note that a false positive (this routine returning true for an object
514  // created on the stack) requires the previous stack value to have been
515  // set to exactly kObjectAllocMemValue at exactly the right position (i.e.
516  // where this object's fUniqueID is located.
517  // The consequence of a false positive will be visible if and only if
518  // the object is auto-added to a TDirectory (i.e. TTree, TH*, TGraph,
519  // TEventList) or explicitly added to the directory by the user
520  // and
521  // the TDirectory (or TFile) object is created on the stack *before*
522  // the object.
523  // The consequence would be that those objects would be deleted twice, once
524  // by the TDirectory and once automatically when going out of scope
525  // (and thus quite visible). A false negative (which is not posible with
526  // this implementation) would have been a silent memory leak.
527 
528  // This will be reported by valgrind as uninitialized memory reads for
529  // object created on the stack, use $ROOTSYS/etc/valgrind-root.supp
530  return *member == kObjectAllocMemValue;
531 }
532 
533 ////////////////////////////////////////////////////////////////////////////////
534 ///return max block size
535 
537 {
538  return fgMaxBlockSize;
539 }
540 
541 ////////////////////////////////////////////////////////////////////////////////
542 ///set max block size
543 
544 void TStorage::SetMaxBlockSize(size_t size)
545 {
546  fgMaxBlockSize = size;
547 }
548 
549 ////////////////////////////////////////////////////////////////////////////////
550 ///return free hook
551 
553 {
554  return fgFreeHook;
555 }
556 
557 #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:29
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:43
static ULong_t GetHeapBegin()
Definition: TStorage.cxx:447
static Bool_t MemCheck()
Return kTRUE if the memory leak checker is on.
Definition: TROOT.cxx:2630
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:456
#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:41
static void AddToHeap(ULong_t begin, ULong_t end)
add a range to the heap
Definition: TStorage.cxx:491
static char * ReAllocChar(char *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition: TStorage.cxx:260
static void * fgFreeHookData
Definition: TStorage.h:39
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:42
static size_t GetMaxBlockSize()
Definition: TStorage.h:112
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:466
static FreeHookFun_t GetFreeHook()
Definition: TStorage.h:116
#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:434
static Bool_t HasCustomNewDelete()
return the has custom delete flag
Definition: TStorage.cxx:474
static void SetCustomNewDelete()
set the has custom delete flag
Definition: TStorage.cxx:482
static Int_t gAllocatedTotal
Definition: TStorage.cxx:82
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:381
#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:371
#define ClassImp(name)
Definition: Rtypes.h:279
static Bool_t IsOnHeap(void *p)
is object at p in the heap?
Definition: TStorage.cxx:499
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: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:28
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:114
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:87
static void ** gTraceArray
Definition: TStorage.cxx:83
const Bool_t kTRUE
Definition: Rtypes.h:91
static ReAllocFun_t fgReAllocHook
Definition: TStorage.h:40
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:354
static void PrintStatistics()
Print memory usage statistics.
Definition: TStorage.cxx:390
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:290