I am trying to fill a TTree with a user-defined class in pyROOT, but ROOT does not seem to be calling the destructor on the class in order to free-up memory. Running this code, the program will continue to allocate memory in RAM until it crashes or finishes.
I have condensed my code in order to reproduce the problem into the following files:
ScopeEvent.C
#include <TGraph.h>
class ScopeEvent
{
public:
ScopeEvent() : fID(-1), fC1(0), fC2(0) { };
ScopeEvent(int id, TGraph *c1, TGraph *c2) : fID(id), fC1(c1), fC2(c2) { };
virtual ~ScopeEvent() { delete fC1; delete fC2; };
int GetID() const { return fID; };
TGraph *GetC1() const { return fC1; };
TGraph *GetC2() const { return fC2; };
void SetID(int id) { fID = id; };
void SetC1(TGraph *c1) { fC1 = c1; };
void SetC2(TGraph *c2) { fC2 = c2; };
void Draw() { fC1->Draw("AL"); fC2->Draw("L SAME"); };
ClassDef(ScopeEvent, 1)
protected:
int fID;
TGraph *fC1, *fC2;
};
ClassImp(ScopeEvent)
import numpy
import ROOT
ROOT.gROOT.ProcessLine(".L ScopeEvent.C+")
f = ROOT.TFile("test.root", 'recreate')
T = ROOT.TTree('T', 'Scope Events')
event = ROOT.ScopeEvent()
T.Branch('event', 'ScopeEvent', event)
for i in range(10000):
x1 = numpy.arange(10000)
y1 = numpy.arange(10000)
x2 = numpy.arange(10000)
y2 = numpy.arange(10000)
c1 = ROOT.TGraph(len(x1), x1, y1)
c2 = ROOT.TGraph(len(x2), x2, y2)
event.SetID(0)
event.SetC1(c1)
event.SetC2(c2)
T.Fill()
f.cd()
T.Write()
f.Close()
I tried everything suggested at http://cern.ch/wlav/pyroot/memory.html, without any luck.
The only solution I found was to add a Clear() function to the ScopeEvent class which deletes the memory from within the object itself:
void Clear() { delete fC1; delete fC2;}
and call this function after every Tree::Fill() command, but unfortunately, all of our analysis software requires that the ScopeEvent class remain unchanged.
I am using ROOT v5.26
Any ideas?