I am trying to build a Go4 analysis which gets TTrees sent from an unpacker through a TSocket and then fills some histograms based on these trees. This means I will read a lot of TTrees. I find that whenever I map them, the memory usage of my program increases slightly. This will eventually become a problem.
I have created a small program which reproduces the problem. If I comment out the lines which map the branches, memory usage is constant.
I don’t see any suspicious in the output from Valgrind (attached). valgrindOutput.zip (609.3 KB)
Am I missing something? Why does memory usage increase when doing this?
To Reproduce
I have this code which produces the problem:
int main() {
auto _adcU1FE = std::shared_ptr<UInt_t>(new UInt_t[16], std::default_delete<UInt_t[]>());
auto _adcU1BE = std::shared_ptr<UInt_t>(new UInt_t[16], std::default_delete<UInt_t[]>());
auto _adcU2FE = std::shared_ptr<UInt_t>(new UInt_t[16], std::default_delete<UInt_t[]>());
auto _adcU2BE = std::shared_ptr<UInt_t>(new UInt_t[16], std::default_delete<UInt_t[]>());
auto file = new TFile("/home/jeppe/Downloads/run_050.root","READ"); //would get TMemFile here instead
auto tree = (TTree*)file->Get("h101");
for(int i = 0; i < 1e8; i++){
tree->SetBranchStatus("*", false);
tree->SetBranchAddress("U1F_E",_adcU1FE.get());
tree->SetBranchAddress("U1B_E",_adcU1BE.get());
tree->SetBranchAddress("U2F_E",_adcU2FE.get());
tree->SetBranchAddress("U2B_E",_adcU2BE.get());
tree->ResetBranchAddresses();
tree->SetBranchStatus("*", false);
}
return 0;
}
ROOT v6.34.08
Built for linuxx8664gcc on Apr 07 2025, 20:24:19
From tags/v6-34-08@v6-34-08
With c++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
Binary directory: /home/jeppe/devel/res/root/bin
Thanks for the post.
I am adding in the loop @pcanal .
Please mind that answers may be posted with some delay during this period, characterised by holidays in some countries.
Thanks for the answer! Writing here to bump up the thread. I have packaged all this into a repository so it’s easier to run:
The code is now, to demonstrate that the memory is not held by the TFile or TTree:
#include "TFile.h"
#include "TTree.h"
int main() {
auto _adcU1FE = std::shared_ptr<UInt_t>(new UInt_t[16], std::default_delete<UInt_t[]>());
auto _adcU1BE = std::shared_ptr<UInt_t>(new UInt_t[16], std::default_delete<UInt_t[]>());
auto _adcU2FE = std::shared_ptr<UInt_t>(new UInt_t[16], std::default_delete<UInt_t[]>());
auto _adcU2BE = std::shared_ptr<UInt_t>(new UInt_t[16], std::default_delete<UInt_t[]>());
for(int i = 0; i < 1e8; i++){
auto file = new TFile("run_059.root","READ");
auto tree = (TTree*)file->Get("h101");
tree->SetBranchAddress("U1F_E",_adcU1FE.get());
tree->SetBranchAddress("U1B_E",_adcU1BE.get());
tree->SetBranchAddress("U2F_E",_adcU2FE.get());
tree->SetBranchAddress("U2B_E",_adcU2BE.get());
file -> Close();
delete file;
}
return 0;
}
Is there any way to get around mapping the branches for each file? They will have same structure. Can I make a basis tree and copy the information from every new tree into it, process the basis tree and then clear the basis tree (while maintaining the tree structure and mapping)?
As a side note, the problem has been solved in time for the upcoming v6.36.00 (i.e. with that version, the original code will have no memory hoarding). The fix is also being backported to the v6.32 and v6.34 patch branches.