//*CMZ : 2.23/04 11/10/99 08.32.36 by Rene Brun
//*CMZ : 2.23/03 18/09/99 19.59.06 by Fons Rademakers
//*CMZ : 2.21/05 08/02/99 12.32.45 by Fons Rademakers
//*CMZ : 2.00/10 14/07/98 18.37.55 by Fons Rademakers
//*CMZ : 2.00/06 09/05/98 15.22.42 by Fons Rademakers
//*-- Author : Fons Rademakers 29/07/95
//*KEEP,CopyRight,T=C.
/*************************************************************************
* Copyright(c) 1995-1999, The ROOT System, All rights reserved. *
* Authors: Rene Brun and Fons Rademakers. *
* *
* For the licensing terms see $ROOTSYS/AA_LICENSE. *
* For the list of contributors see $ROOTSYS/AA_CREDITS. *
*************************************************************************/
//*KEND.
//////////////////////////////////////////////////////////////////////////
// //
// TStorage //
// //
// Storage manager. The storage manager works best in conjunction with //
// the custom ROOT new and delete operators defined in the file //
// NEW_NewDelete.cxx (libNew.so). Only when using the custom allocation //
// operators will memory usage statistics be gathered using the //
// TStorage EnterStat(), RemoveStat(), etc. functions. //
// Memory checking is by default enabled (when using libNew.so) and //
// usage statistics is gathered. Using the resource (in .rootrc): //
// Root.MemStat one can toggle statistics gathering on or off. More //
// specifically on can trap the allocation of a block of memory of a //
// certain size. This can be specified using the resource: //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can //
// specify after how many allocations of this size the trap should //
// occur. //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system. //
// //
//////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <errno.h>
//*KEEP,TObjectTable.
#include "TObjectTable.h"
//*KEEP,TError.
#include "TError.h"
//*KEEP,TMath.
#include "TMath.h"
//*KEEP,TString.
#include "TString.h"
//*KEND.
#if !defined(R__NOSTATS)
# define MEM_DEBUG
# define MEM_STAT
# define MEM_CHECKOBJECTPOINTERS
#endif
#if defined(MEM_STAT) && !defined(MEM_DEBUG)
# define MEM_DEBUG
#endif
#ifdef MEM_DEBUG
# define storage_size(p) ((size_t)(((int*)p)[-2]))
#else
# define storage_size(p) ((size_t)0)
#endif
ULong_t TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t TStorage::fgHeapEnd;
size_t TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void *TStorage::fgFreeHookData;
ReAllocFun_t TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t TStorage::fgHasCustomNewDelete;
ClassImp(TStorage)
//------------------------------------------------------------------------------
static const char *spaceErr = "storage exhausted";
const size_t kObjMaxSize = 10024;
static Bool_t memStatistics;
static Int_t allocated[kObjMaxSize], freed[kObjMaxSize];
static Int_t allocatedTotal, freedTotal;
static void **traceArray = 0;
static Int_t traceCapacity = 10, traceIndex = 0, memSize = -1, memIndex = -1;
//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
// Register a memory allocation operation. If desired one can trap an
// allocation of a certain size in case one tries to find a memory
// leak of that particular size. This function is only called via
// the ROOT custom new operators.
TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));
if (!memStatistics) return;
if ((Int_t)size == memSize) {
if (traceIndex == memIndex)
Fatal("EnterStat", "trapped allocation %d", memIndex);
if (!traceArray) traceArray = (void**) malloc(sizeof(void*)*traceCapacity);
if (traceIndex >= traceCapacity) {
traceCapacity = traceCapacity*2;
traceArray = (void**) realloc(traceArray, sizeof(void*)*traceCapacity);
}
traceArray[traceIndex++] = p;
}
if (size >= kObjMaxSize)
allocated[kObjMaxSize-1]++;
else
allocated[size]++;
allocatedTotal += size;
}
//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
// Register a memory free operation. This function is only called via
// the custom ROOT delete operator.
if (!memStatistics) return;
size_t size = storage_size(vp);
if ((Int_t)size == memSize) {
for (int i = 0; i < traceIndex; i++)
if (traceArray[i] == vp) {
traceArray[i] = 0;
break;
}
}
if (size >= kObjMaxSize)
freed[kObjMaxSize-1]++;
else
freed[size]++;
freedTotal += size;
}
//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
// Reallocate (i.e. resize) block of memory.
if (fgReAllocHook && fgHasCustomNewDelete)
return (*fgReAllocHook)(ovp, size);
static const char *where = "TStorage::ReAlloc";
char *vp;
if (ovp == 0) {
vp = new char [size];
if (vp == 0)
Fatal(where, spaceErr);
return vp;
}
vp = new char [size];
if (vp == 0)
Fatal(where, spaceErr);
memmove(vp, ovp, size);
delete [] (char *) ovp;
return vp;
}
//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
{
// Reallocate (i.e. resize) block of memory. Checks if current size is
// equal to oldsize. If not memory was overwritten.
if (fgReAllocCHook && fgHasCustomNewDelete)
return (*fgReAllocCHook)(ovp, size, oldsize);
static const char *where = "TStorage::ReAlloc";
char *vp;
if (ovp == 0) {
vp = new char [size];
if (vp == 0)
Fatal(where, spaceErr);
return vp;
}
if (oldsize == size)
return ovp;
vp = new char [size];
if (vp == 0)
Fatal(where, spaceErr);
if (size > oldsize) {
memcpy(vp, ovp, oldsize);
memset(vp+oldsize, 0, size-oldsize);
} else
memcpy(vp, ovp, size);
delete [] (char *) ovp;
return vp;
}
//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t sz)
{
// Used to allocate a TObject on the heap (via TObject::new()). Directly
// after this routine one can call (in the TObject ctor) TStorage::IsOnHeap()
// to find out if the just created object is on the heap.
ULong_t space = (ULong_t) new char[sz];
AddToHeap(space, space+sz);
return (void*) space;
}
//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t , void *vp)
{
// Used to allocate a TObject on the heap (via TObject::new(size_t,void*))
// in position vp. vp is already allocated (maybe on heap, maybe on
// stack) so just return.
return vp;
}
//______________________________________________________________________________
void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
{
// Set a free handler.
fgFreeHook = fh;
fgFreeHookData = data;
}
//______________________________________________________________________________
void TStorage::SetReAllocHooks(ReAllocFun_t rh1, ReAllocCFun_t rh2)
{
// Set a custom ReAlloc handlers. This function is typically
// called via a static object in the ROOT libNew.so shared library.
fgReAllocHook = rh1;
fgReAllocCHook = rh2;
}
//______________________________________________________________________________
void TStorage::PrintStatistics()
{
// Print memory usage statistics.
#if defined(MEM_DEBUG) && defined(MEM_STAT)
if (!memStatistics || !HasCustomNewDelete())
return;
//Printf("");
Printf("Heap statistics");
Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
Printf("================================================");
int i;
for (i = 0; i < (int)kObjMaxSize; i++)
if (allocated[i] != freed[i])
//if (allocated[i])
Printf("%12d%12d%12d%12d", i, allocated[i], freed[i],
allocated[i]-freed[i]);
if (allocatedTotal != freedTotal) {
Printf("------------------------------------------------");
Printf("Total: %12d%12d%12d", allocatedTotal, freedTotal,
allocatedTotal-freedTotal);
}
if (memSize != -1) {
Printf("------------------------------------------------");
for (i= 0; i < traceIndex; i++)
if (traceArray[i])
Printf("block %d of size %d not freed", i, memSize);
}
Printf("================================================");
Printf("");
#endif
}
//______________________________________________________________________________
void TStorage::EnableStatistics(int size, int ix)
{
// Enable memory usage statistics gathering. Size is the size of the memory
// block that should be trapped and ix is after how many such allocations
// the trap should happen.
#ifdef MEM_STAT
memSize = size;
memIndex = ix;
memStatistics = kTRUE;
#else
int idum = size; int iidum = ix;
#endif
}
//______________________________________________________________________________
ULong_t TStorage::GetHeapBegin()
{
return fgHeapBegin;
}
//______________________________________________________________________________
ULong_t TStorage::GetHeapEnd()
{
return fgHeapEnd;
}
//______________________________________________________________________________
void *TStorage::GetFreeHookData()
{
return fgFreeHookData;
}
//______________________________________________________________________________
Bool_t TStorage::HasCustomNewDelete()
{
return fgHasCustomNewDelete;
}
//______________________________________________________________________________
void TStorage::SetCustomNewDelete()
{
fgHasCustomNewDelete = kTRUE;
}
#ifdef WIN32
//______________________________________________________________________________
size_t TStorage::GetMaxBlockSize()
{
return fgMaxBlockSize;
}
//______________________________________________________________________________
void TStorage::SetMaxBlockSize(size_t size)
{
fgMaxBlockSize = size;
}
//______________________________________________________________________________
FreeHookFun_t TStorage::GetFreeHook()
{
return fgFreeHook;
}
#endif
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.