We have an program that was written a while ago, which reads TTrees containing custom objects. In ROOT 5, this works as expected. In ROOT 6, it leaks memory like it’s going out of style.
The objects we are storing in the tree contain a pointer to another object, which allocates memory. Let’s call the objects in the TTree MyTreeElem
, each of which contains a pointer to a MyObj
on the heap, which also contains pointers to memory allocated for that class.
eg:
class MyObj : public TObject {
public:
void * someblock;
MyObj() : someblock(new void[100]);
~MyObj() { delete someblock; }
}
class TreeElem : public TObject {
public:
MyObj * content;
TreeElem() { content(new MyObj()); }
~TreeElem() { delete content; }
}
We set up to read our tree, and read a couple of elements.
TTree * mytree = ... // get from some file
MyTreeElem * elem = 0;
mytree->SetBranchAddress("myelem",&elem);
mytree->GetEntry(0);
mytree->GetEntry(1);
When built against ROOT5, when we get the second entry in the tree, it appears that ~MyTreeElem()
is not called but ~MyObj()
is called, cleaning up the memory assigned by the heap MyObj
owned by the MyTreeElem
.
When built against ROOT6, the~MyObj()
method is not called when getting the next entry, meaning that without a manual cleanup call the program leaks memory extremely rapidly.
I can get around this by setting TBranch::SetAutoDelete(kTrue);
, which leads to a call to ~MyTreeElem()
, which cleans up the other objects too. The documentation, however, suggests that using SetAutoDelete() is to be avoided. On top of this, we would require the SetAutoDelete() in every script that reads these files. Other forms of loop that do not include this call also leak dangerously, like a python loop
for event in mytree:
print event.myelem;
Can someone explain what exactly has changed here, why it was changed and how I can continue to have files that behave as people expect, without requiring extra steps to prevent leakage?
Thanks in advance.