// @(#)root/new:$Id$ // Author: D.Bertini and M.Ivanov 10/08/2000 /************************************************************************* * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ //****************************************************************************// // // // MemCheck is used to check the memory in ROOT based applications. // // Principe: // A memory leak often arises whenever memory allocated through // (new, new[]) is never returned via a corresponding (delete, delete[]). // Redefining a special version of (operator new, operator delete) will // allow the bookkeeping of created pointers to chunks of memory and, at // the same time, pointers to the current function (and all of its callers // scanning the stack) in order to trace back where the memory is not freed. // This specific bookkeeping of pointers will be done by a kind of // "memory info" container class TMemHashTable that will be used via // the ROOT memory management defined inside the NewDelete.cxx file. // // To activate the memory checker you have to set in the .rootrc file // the resource Root.MemCheck to 1 (e.g.: Root.MemCheck: 1) and you // have to link with libNew.so (e.g. use root-config --new --libs) or // use rootn.exe. When all this is the case you will find at the end // of the program execution a file "memcheck.out" in the directory // where you started your ROOT program. Alternatively you can set // the resource Root.MemCheckFile to the name of a file to which // the leak information will be written. The contents of this // "memcheck.out" file can be analyzed and transformed into printable // text via the memprobe program (in $ROOTSYS/bin). // // (c) 2000 : Gesellschaft fuer Schwerionenforschung GmbH // Planckstrasse, 1 // D-64291 Darmstadt // Germany // // Created 10/08/2000 by: D.Bertini and M.Ivanov. // Based on ideas from LeakTracer by Erwin Andreasen. // // - Updated: // Date: 12/02/2001 Adapt script to new GDB 5.0, new glibc2.2.x and gcc 2.96. // Date: 23/10/2000 (hash mechanism speeding up the bookkeeping) // // - Documentation: // // http://www-hades.gsi.de/~dbertini/mem.html // //****************************************************************************// #include "TROOT.h" class TStackInfo { public: UInt_t fSize; //size of the stack Int_t fTotalAllocCount; //total number of allocation for stack sequence Int_t fTotalAllocSize; //total size of allocated memory Int_t fAllocCount; //current number of allocation-deallocation Int_t fAllocSize; //current allocated size TStackInfo *fNextHash; //index-pointer to the next info for given hash value public: void Init(Int_t stacksize, void **stackptrs); //initialization void Inc(Int_t memSize); //increment counters -when memory allocated void Dec(Int_t memSize); //decrement counters -when memory deallocated ULong_t Hash(); Int_t IsEqual(UInt_t size, void **ptr); void *StackAt(UInt_t i); TStackInfo *Next(); //index of the next entries static ULong_t HashStack(UInt_t size, void **ptr); }; class TStackTable { private: char *fTable; //pointer to the table TStackInfo **fHashTable; //pointer to the hash table Int_t fSize; //current size of the table Int_t fHashSize; //current size of the hash table Int_t fCount; //number of entries in table char *fNext; //pointer to the last stack info void Expand(Int_t newsize); public: void Init(); TStackInfo *AddInfo(Int_t size, void **stackptrs); TStackInfo *FindInfo(Int_t size, void **stackptrs); Int_t GetIndex(TStackInfo *info); TStackInfo *GetInfo(Int_t index); TStackInfo *First() { return (TStackInfo *)fTable; } }; class TMemInfo { public: void *fAddress; //mem address size_t fSize; //size of the allocated memory Int_t fStackIndex; //index of the stack info }; class TMemTable { public: Int_t fAllocCount; //number of memory allocation blocks Int_t fMemSize; //total memory allocated size Int_t fTableSize; //amount of entries in the below array Int_t fFirstFreeSpot; //where is the first free spot in the leaks array? TMemInfo *fLeaks; //leak table }; class TDeleteTable { public: Int_t fAllocCount; //how many memory blocks do we have Int_t fTableSize; //amount of entries in the below array TMemInfo *fLeaks; //leak table }; class TMemHashTable { public: static Int_t fgSize; //size of hash table static TMemTable **fgLeak; //pointer to the hash table static Int_t fgAllocCount; //number of memory allocation blocks static TStackTable fgStackTable; //table with stack pointers static TDeleteTable fgMultDeleteTable; //pointer to the table ~TMemHashTable() { if (TROOT::MemCheck()) Dump(); } static void Init(); static void RehashLeak(Int_t newSize); //rehash leak pointers static void *AddPointer(size_t size, void *ptr=0); //add pointer to the table static void FreePointer(void *p); //free pointer static void Dump(); //write leaks to the output file }; inline void TStackInfo::Inc(Int_t memSize) { fTotalAllocCount += 1; fTotalAllocSize += memSize; fAllocCount += 1; fAllocSize += memSize; } inline void TStackInfo::Dec(int memSize) { fAllocCount -= 1; fAllocSize -= memSize; } inline ULong_t TStackInfo::Hash() { return HashStack(fSize, (void**)&(this[1])); } inline void *TStackInfo::StackAt(UInt_t i) { //return i