Memory leak in ROOT

Hi there,

I have a program that provides tracking in our detector on an event by event basis.
This means that every time I run it, I’m able to to display some tracks and fits for one event.
This program already has some memory issue in the sense that I can’t run it more than 4 or 5 times without freezing my computer (it’s a fairly big program that does a lot a things). But this is not this issue.

I’m trying to write a Batch mode version of this program which could run over thousands of events and output the data I want (track angle, Chi square etc…).
The memory leak is now becoming a issue of course and my program usually crashes after about 2000 events.

Curious to discover where this memory leak could come from, I started to look at very small portion of the program and I discover that I already see a significant issue with memory at the the very beginning (before I even do anything).

Here’s the few first lines of my code:

#ifndef CINT
#include <stdio.h>
#include <math.h>
#include
#include
#include
#include <string.h>
#include
#include
#include <TROOT.h>
#include “TSystem.h”
#include “TFile.h”
#include “TProfile.h”
#include “TChain.h”
#include “TH1F.h”
#include “TH1D.h”
#include “TH2F.h”
#include “TF1.h”
#include “TGaxis.h”
#include “TRandom.h”
#include “TNtuple.h”
#include “TCanvas.h”
#include “TPolyLine.h”
#include “TLine.h”
#include “TArrow.h”
#include “TStyle.h”
#include “TGraphErrors.h”
#include “TGraph.h”
#include “TBranch.h”
#include “TLegend.h”
#include “TLatex.h”
#include “TEllipse.h”
#include “TMarker.h”
#include “ANAPATH.h”
#include “CommonParameters.h”
#include “ADC_Thresholds.h”
#include “TDC_Windows.h”
#include “Cuts_and_Windows.h”
#include “MWPC_Thr.h”
#endif

using namespace std;

void Batch_Test(Int_t Run_Number=5, Int_t ievt_min=2, Int_t ievt_max=2){

gROOT->SetBatch(1);

gStyle->Clear();
TH1::AddDirectory(kFALSE);
gStyle->SetOptStat(11);

int HG_TARGET_ADC_Thr[256];

char h_target_ADC_title[100];
char h_target_TDC_title[100];
char h_target_TDC_copy_Title[200];
char h_TDC_selected_Title[200];
char h_TDC_selected2_Title[200];

char h_target_TDC_copy_Name[200];
char h_TDC_selected_Name[200];
char h_TDC_selected2_Name[200];

Int_t TDC_min_TARGET = TARGET_TDC_min[0];
Int_t TDC_max_TARGET = TARGET_TDC_max[0];
Int_t ADC_TARGET_Thr = HG_TARGET_ADC_Thr[0];
Int_t TDC_min_SFT = SFT_TDC_min[0];
Int_t TDC_max_SFT = SFT_TDC_max[0];

sprintf(h_target_ADC_title,“Run %d (Event %d) – ADC #geq %d)”,Run_Number, ievt_min, ADC_TARGET_Thr);
sprintf(h_target_TDC_title,“Run %d (Event %d) – ADC #geq %d | %d #leq TDC #leq %d”,Run_Number, ievt_min, ADC_TARGET_Thr,TDC_min_TARGET,TDC_max_TARGET);
sprintf(h_target_TDC_copy_Title,“ADC_HG #geq %d | %d #leq TDC #leq %d”, ADC_TARGET_Thr, TDC_min_TARGET, TDC_max_TARGET);
sprintf(h_TDC_selected_Title,“ADC_HG #geq %d | %d #leq TDC #leq %d”, ADC_TARGET_Thr+100, TDC_min_TARGET, TDC_max_TARGET);
sprintf(h_TDC_selected2_Title,“ADC_HG #geq %d | %d #leq TDC #leq %d (WEIGHTED)”, ADC_TARGET_Thr+100,TDC_min_TARGET,TDC_max_TARGET);

sprintf(h_target_TDC_copy_Name,“Event %d (Run %d)”, ievt_min, Run_Number);
sprintf(h_TDC_selected_Name,“Event %d (Run %d)”, ievt_min, Run_Number);
sprintf(h_TDC_selected2_Name,“Event %d (Run %d)”, ievt_min, Run_Number);

TH2F *h_target_ADC = new TH2F(“Histo Fit 0”,h_target_ADC_title,3000,-50,50,3000,-50,50);
TH2F *h_target_TDC = new TH2F(“Histo Fit 1”,h_target_TDC_title,3000,-50,50,3000,-50,50);
TH2F *h_target_TDC_copy = new TH2F(h_target_TDC_copy_Name,h_target_TDC_copy_Title,3000,-50,50,3000,-50,50);
TH2F *h_TDC_selected = new TH2F(h_TDC_selected_Name, h_TDC_selected_Title, 500, -50, 50, 500, -50, 50);
TH2F *h_TDC_selected2 = new TH2F(h_TDC_selected2_Name, h_TDC_selected2_Title, 500, -50, 50, 500, -50, 50);

h_target_ADC->Reset();
h_target_TDC->Reset();
h_target_TDC_copy->Reset();
h_TDC_selected->Reset();
h_TDC_selected2->Reset();
}

As you can see, I’m not doing anything else than declaring a few histograms.
Yet, when I execute this small part of a program, it takes quite a chunk of memory that I recover ONLY after I leave ROOT (.q)

Do you know why I don’t recover the memory used during execution after each execution of the program ?

Thank you very much for your support,

Call at the end of your code:

if(!gROOT->IsBatch()) return;

delete h_target_ADC;
delete h_target_TDC;
delete h_target_TDC_copy;
delete h_TDC_selected;
delete h_TDC_selected2;

You can test your memory issues with:

valgrind --suppressions=$ROOTSYS/etc/valgrind-root.supp --leak-check=full --log-file=valgrind.log root.exe -n -l Batch_Test.cpp+

TH2F *h_target_ADC = new TH2F("Histo Fit 0",h_target_ADC_title,3000,-50,50,3000,-50,50);As you probably notice, just this histograms already takes 230003000*sizeof(float) equals roughly 68Mb …

[quote]The memory leak is now becoming a issue of course and my program usually crashes after about 2000 events.[/quote]I am not seeing in the portion of code, the loop over the events. Any memory leaks would be induced by the code within that loop.

Cheers,
Philippe.

Thank you very much.
Adding “delete…” helped a lot.

Now, I have a problem when I got to the loop over events.
I have the same problem. Every time I run this loop, I loose memory.
If I run over a few events, after it ran, the memory isn’t given back and if I run more events (something like a million or so), the program doesn’t even run until the end.

Here, the first few lines of the loop over the events (the actual program is way bigger).
Thank you again very much for your help.

[code] for(int ivt=ievt_min; ivt<ievt_max+1; ivt++){
if((ivt-ievt_min)%100==0 && (ivt-ievt_min)!=0) cout << “*** " << (ivt-ievt_min) << " events done!” << endl;

fChain->GetEntry(ivt);  

for(int i=0; i<256; i++)  HG_TARGET_ADC_Thr[i] = round(TARGET_ADC_Thr_HG[i]) + TARGET_ADC_Thr_HG_Offset;
for(int i=0; i<256; i++)  LG_TARGET_ADC_Thr[i] = round(TARGET_ADC_Thr_LG[i]) + TARGET_ADC_Thr_LG_Offset;
for(int i=0; i<128; i++)  HG_SFT_ADC_Thr[i] = round(SFT_ADC_Thr_HG[i]) + SFT_ADC_Thr_HG_Offset;
//for(int i=0; i<128; i++)  LG_SFT_ADC_Thr[i] = round(SFT_ADC_Thr_LG[i]) + SFT_ADC_Thr_LG_Offset;


for (int j_TARGET=0; j_TARGET<256; j_TARGET++){
  ADC_High_TARGET[j_TARGET]=adc_high_target[j_TARGET]-HG_TARGET_ADC_Thr[j_TARGET];
  ADC_High_TARGET_ped[j_TARGET]=adc_high_target[j_TARGET]-HG_TARGET_ADC_Thr[j_TARGET] + TARGET_ADC_Thr_HG_Offset;
  ADC_Low_TARGET[j_TARGET]=adc_low_target[j_TARGET]-LG_TARGET_ADC_Thr[j_TARGET];
  ADC_Low_TARGET_ped[j_TARGET]=adc_low_target[j_TARGET]-LG_TARGET_ADC_Thr[j_TARGET] + TARGET_ADC_Thr_LG_Offset; 
  //TDC_LE_TARGET[j_TARGET]=tdc_le_target[j_TARGET][0];
} 

}
[/code]

Even when I only run this, it takes memory that I don’t get back after the loop:

for(int ivt=ievt_min; ivt<ievt_max+1; ivt++){ fChain->GetEntry(ivt); }

NOTE: Everything BEFORE the loop if fine

How do you define your branches? In some cases, if I recall correctly, the ownership of the object is not taken by the tree, so that you need to delete manually the pointer after processing.

See: root.cern.ch/doc/master/classTTree.html and search for "owner"
And also: Std vector pointer branch and memory leak