00001 // @(#)root/new:$Id: MemCheck.h 20882 2007-11-19 11:31:26Z rdm $ 00002 // Author: D.Bertini and M.Ivanov 10/08/2000 00003 00004 /************************************************************************* 00005 * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. * 00006 * All rights reserved. * 00007 * * 00008 * For the licensing terms see $ROOTSYS/LICENSE. * 00009 * For the list of contributors see $ROOTSYS/README/CREDITS. * 00010 *************************************************************************/ 00011 00012 //****************************************************************************// 00013 // 00014 // 00015 // MemCheck is used to check the memory in ROOT based applications. 00016 // 00017 // Principe: 00018 // A memory leak often arises whenever memory allocated through 00019 // (new, new[]) is never returned via a corresponding (delete, delete[]). 00020 // Redefining a special version of (operator new, operator delete) will 00021 // allow the bookkeeping of created pointers to chunks of memory and, at 00022 // the same time, pointers to the current function (and all of its callers 00023 // scanning the stack) in order to trace back where the memory is not freed. 00024 // This specific bookkeeping of pointers will be done by a kind of 00025 // "memory info" container class TMemHashTable that will be used via 00026 // the ROOT memory management defined inside the NewDelete.cxx file. 00027 // 00028 // To activate the memory checker you have to set in the .rootrc file 00029 // the resource Root.MemCheck to 1 (e.g.: Root.MemCheck: 1) and you 00030 // have to link with libNew.so (e.g. use root-config --new --libs) or 00031 // use rootn.exe. When all this is the case you will find at the end 00032 // of the program execution a file "memcheck.out" in the directory 00033 // where you started your ROOT program. Alternatively you can set 00034 // the resource Root.MemCheckFile to the name of a file to which 00035 // the leak information will be written. The contents of this 00036 // "memcheck.out" file can be analyzed and transformed into printable 00037 // text via the memprobe program (in $ROOTSYS/bin). 00038 // 00039 // (c) 2000 : Gesellschaft fuer Schwerionenforschung GmbH 00040 // Planckstrasse, 1 00041 // D-64291 Darmstadt 00042 // Germany 00043 // 00044 // Created 10/08/2000 by: D.Bertini and M.Ivanov. 00045 // Based on ideas from LeakTracer by Erwin Andreasen. 00046 // 00047 // - Updated: 00048 // Date: 12/02/2001 Adapt script to new GDB 5.0, new glibc2.2.x and gcc 2.96. 00049 // Date: 23/10/2000 (hash mechanism speeding up the bookkeeping) 00050 // 00051 // - Documentation: 00052 // 00053 // http://www-hades.gsi.de/~dbertini/mem.html 00054 // 00055 //****************************************************************************// 00056 00057 #include "TROOT.h" 00058 00059 00060 class TStackInfo { 00061 public: 00062 UInt_t fSize; //size of the stack 00063 Int_t fTotalAllocCount; //total number of allocation for stack sequence 00064 Int_t fTotalAllocSize; //total size of allocated memory 00065 Int_t fAllocCount; //current number of allocation-deallocation 00066 Int_t fAllocSize; //current allocated size 00067 TStackInfo *fNextHash; //index-pointer to the next info for given hash value 00068 00069 public: 00070 void Init(Int_t stacksize, void **stackptrs); //initialization 00071 void Inc(Int_t memSize); //increment counters -when memory allocated 00072 void Dec(Int_t memSize); //decrement counters -when memory deallocated 00073 ULong_t Hash(); 00074 Int_t IsEqual(UInt_t size, void **ptr); 00075 void *StackAt(UInt_t i); 00076 TStackInfo *Next(); //index of the next entries 00077 00078 static ULong_t HashStack(UInt_t size, void **ptr); 00079 }; 00080 00081 00082 class TStackTable { 00083 private: 00084 char *fTable; //pointer to the table 00085 TStackInfo **fHashTable; //pointer to the hash table 00086 Int_t fSize; //current size of the table 00087 Int_t fHashSize; //current size of the hash table 00088 Int_t fCount; //number of entries in table 00089 char *fNext; //pointer to the last stack info 00090 00091 void Expand(Int_t newsize); 00092 00093 public: 00094 void Init(); 00095 TStackInfo *AddInfo(Int_t size, void **stackptrs); 00096 TStackInfo *FindInfo(Int_t size, void **stackptrs); 00097 Int_t GetIndex(TStackInfo *info); 00098 TStackInfo *GetInfo(Int_t index); 00099 TStackInfo *First() { return (TStackInfo *)fTable; } 00100 }; 00101 00102 00103 class TMemInfo { 00104 public: 00105 void *fAddress; //mem address 00106 size_t fSize; //size of the allocated memory 00107 Int_t fStackIndex; //index of the stack info 00108 }; 00109 00110 class TMemTable { 00111 public: 00112 Int_t fAllocCount; //number of memory allocation blocks 00113 Int_t fMemSize; //total memory allocated size 00114 Int_t fTableSize; //amount of entries in the below array 00115 Int_t fFirstFreeSpot; //where is the first free spot in the leaks array? 00116 TMemInfo *fLeaks; //leak table 00117 }; 00118 00119 class TDeleteTable { 00120 public: 00121 Int_t fAllocCount; //how many memory blocks do we have 00122 Int_t fTableSize; //amount of entries in the below array 00123 TMemInfo *fLeaks; //leak table 00124 }; 00125 00126 00127 class TMemHashTable { 00128 public: 00129 static Int_t fgSize; //size of hash table 00130 static TMemTable **fgLeak; //pointer to the hash table 00131 static Int_t fgAllocCount; //number of memory allocation blocks 00132 static TStackTable fgStackTable; //table with stack pointers 00133 static TDeleteTable fgMultDeleteTable; //pointer to the table 00134 00135 ~TMemHashTable() { if (TROOT::MemCheck()) Dump(); } 00136 00137 static void Init(); 00138 static void RehashLeak(Int_t newSize); //rehash leak pointers 00139 static void *AddPointer(size_t size, void *ptr=0); //add pointer to the table 00140 static void FreePointer(void *p); //free pointer 00141 static void Dump(); //write leaks to the output file 00142 }; 00143 00144 00145 00146 inline void TStackInfo::Inc(Int_t memSize) 00147 { 00148 fTotalAllocCount += 1; 00149 fTotalAllocSize += memSize; 00150 fAllocCount += 1; 00151 fAllocSize += memSize; 00152 } 00153 00154 inline void TStackInfo::Dec(int memSize) 00155 { 00156 fAllocCount -= 1; 00157 fAllocSize -= memSize; 00158 } 00159 00160 inline ULong_t TStackInfo::Hash() 00161 { 00162 return HashStack(fSize, (void**)&(this[1])); 00163 } 00164 00165 inline void *TStackInfo::StackAt(UInt_t i) 00166 { 00167 //return i<fSize ? ((char*)&(this[1]))+i*sizeof(void*):0; 00168 void **stptr = (void**)&(this[1]); 00169 return i < fSize ? stptr[i] : 0; 00170 } 00171 00172 inline TStackInfo *TStackInfo::Next() 00173 { 00174 //return (TStackInfo*)((char*)(&this[1])+fSize*sizeof(void*)); 00175 return (TStackInfo*)((char*)(this)+fSize*sizeof(void*)+sizeof(TStackInfo)); 00176 }