Tricky (to me) memory leak when creating a TGraphErrors using copy constructor

I am creating a TGraphErrors using the copy constructor from another TGraphErrors that already exists in memory, and I am getting warnings about potential memory leaks that I can’t understand:

TGraphErrors *gGMp_Ratio_newRC = new TGraphErrors( *gGMp );

gGMp_Ratio_newRC->SetName("gGMp_Ratio_newRC");

“gGMp” is a TGraphErrors that already exists “in memory” or technically in a ROOT file that has been opened for writing, that was already allocated using “new TGraphErrors(…)”.

I get the following warning when I create this graph:

Warning in TFile::Append: Replacing existing TH1: gGMp_Ratio_newRC (Potential memory leak).

It doesn’t appear to be causing any problems with any of the various objects being created and written to the file. However, I am a bit surprised by this behavior/warning because I never told ROOT to write this new object to the file and nothing else is done to it other than to loop over the points and use SetPoint(…) and SetPointError(…).

Some additional details: this warning only appears after the (compiled) macro completes its execution and control is returned to the interactive ROOT session…

It also appears regardless of whether and when I do or don’t write either the original TGraphErrors or the copied one to the file.

So what gives?


Please read tips for efficient and successful posting and posting code

ROOT Version: 6.22.02
Platform: Mac OS Catalina 10.15.7
Compiler: clang Xcode 12.4


Can it be that you have a histogram with this name?
Before these two lines and also after them, try to add:
gROOT->ls(); if (gFile) gFile->ls(); if (gPad) gPad->ls();

You could also try to use:
TGraphErrors *gGMp_Ratio_newRC = ((TGraphErrors*)(gGMp->Clone("gGMp_Ratio_newRC")));

Thanks, I’ll try these and let you know what I find

@Axel or anybody who cares. There is indeed a serious bug in the TGraph / TGraphErrors copy constructors in ROOT 6 (ROOT 5 is fine):

{
  TFile *f = TFile::Open("trial.root", "RECREATE");
  const Int_t n = 20;
  Double_t x[n], y[n];
  for (Int_t i = 0; i < n; i++) { x[i] = i*0.1; y[i] = 10*sin(x[i]+0.2); }
  TGraph *g = new TGraph(n,x,y);
  TCanvas *c = new TCanvas("c","A Simple Graph Example",200,10,700,500);
  // the next two lines will create a histogram (for the frame) ...
  g->Draw("AC*"); // ... but this histogram WILL NOT be stored in the file
  c->Modified(); c->Update(); // make sure it's really (re)drawn
  // this WILL NOT store the histogram in the file
  TGraph *g2 = ((TGraph*)(g->Clone()));
  // this WILL store the histogram in the file
  TGraph *g3 = new TGraph(*g);
  f->Write();
  f->ls(); // ROOT 6 gives: "KEY: TH1F Graph;1 Graph"
  delete f;
}

Tested on Ubuntu 20.04.2 LTS / x86_64, gcc 9.3.0, ROOT “v6-22-00-patches” and “v5-34-00-patches”.

I create issue on github TGraph copy constructor error · Issue #7302 · root-project/root · GitHub
Hope it can be fixed easily

Okay, so I added the ls() commands to my macro as you suggested, and here are my findings:

  1. Before the graph creation via copy constructor, there is no object with the same name.
TFile**		temp.root	
 TFile*		temp.root	
  OBJ: TH1D	hchi2contr	 : 0 at: 0x7fdb67ad0af0
  OBJ: TH2D	hframe_LTs	 : 0 at: 0x7fdb60f92000
  OBJ: TH1D	hframe_Q2eps	 : 0 at: 0x7fdb3ff2c2e0
  OBJ: TH1D	hframe_GMp	 : 0 at: 0x7fdb3ff2f9a0
  OBJ: TH2D	hframe_RS	 : 0 at: 0x7fdb6043c000
  OBJ: TH2D	hframe_TPE	 : 0 at: 0x7fdb63b86000
  KEY: TGraphErrors	gGMp;1	
  KEY: TGraph	gGMpError;1	Graph
  KEY: TGraphErrors	gRp;1	Graph
  KEY: TGraph	gRpError;1	Graph
  KEY: TGraphErrors	gRp2;1	Graph
  KEY: TGraphErrors	gDataFitRatio_vs_Q2;1	
  KEY: TGraphErrors	gDataFitRatio_vs_EPS;1	
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_1;1	Q^{2} =  5.99 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_2;1	Q^{2} =  7.02 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_3;1	Q^{2} =  7.94 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_4;1	Q^{2} =  8.99 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_5;1	Q^{2} =  9.84 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_6;1	Q^{2} = 12.25 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_7;1	Q^{2} = 15.72 (GeV/c)^{2}
  KEY: TGraphErrors	gRp2_LT;1	Graph
  KEY: TGraphErrors	gGMp_LT;1	Graph
  KEY: TGraphErrors	gRp_LT;1	Graph
  KEY: TMultiGraph	mgr_GM;1	
  KEY: TGraphErrors	gRp2_PT;1	#mu_{p}G_{E}^{p} / G_{M}^{p} = #mu_{p}(1 - #tau F_{2} / F_{1}) / (1 + F_{2} / F_{1})
  KEY: TGraphErrors	gDeltaTPE;1	Graph
  KEY: TGraphAsymmErrors	gRp_LTasym;1	Graph
  KEY: TGraph	gTension;1	
  KEY: TGraph	gConfidence;1	Graph
  KEY: TGraphErrors	GMp_Kirk;1	
  KEY: TGraphErrors	GMp_Rock;1	
  KEY: TGraphErrors	GMp_Sill;1	
  KEY: TGraphErrors	GMp_Christy;1	
  KEY: TGraphErrors	GMp_GMp12L;1	
  KEY: TGraphErrors	GMp_GMp12R;1	
  KEY: TGraphErrors	GMp_Andivahis_1;1	
  KEY: TGraphErrors	GMp_Andivahis_2;1	
  KEY: TGraphErrors	GMp_Walker;1	
  KEY: TH1D	hchi2contr;1	
  KEY: TGraphErrors	gsigR_PT_box1;1	Graph
  KEY: TGraphErrors	gsigR_PT_box2;1	Graph
  KEY: TGraphErrors	gsigR_PT_box3;1	Graph
  KEY: TGraphErrors	gsigR_PT_box4;1	Graph
  KEY: TGraphErrors	gsigR_PT_box5;1	Graph
  KEY: TGraphErrors	gsigR_PT_box6;1	Graph
  KEY: TGraphErrors	gsigR_PT_box7;1	Graph
  KEY: TGraph	gdRp2;1	
Canvas Name=c13 Title=c13 Option=
 TCanvas fXlowNDC=0 fYlowNDC=0 fWNDC=1 fHNDC=1 Name= c13 Title= c13 Option=
  OBJ: TList	TList	Doubly linked list : 0
   OBJ: TH2D	hframe_TPE	 : 0 at: 0x7fdb63b86000
   TLine  X1=0.000000 Y1=0.000000 X2=20.000000 Y2=0.000000
   OBJ: TGraphErrors	Graph	Graph : 0 at: 0x7fdb3ff39400
   OBJ: TGraphErrors	Graph	 : 0 at: 0x7fdb68287200
   OBJ: TLegend	TPave  	X1= 5.000000 Y1=0.060000 X2=18.000000 Y2=0.110000
  1. AFTER the graph creation via copy constructor, it appears that there are two objects with the same name, one of which is a TH1F. Interestingly enough, by this stage the original TGraphErrors, gGMp, has already been written to the file and also drawn in one or more canvases. Could this be a symptom of the bug you identified below?
after graph creation: 

TFile**		temp.root	
 TFile*		temp.root	
  OBJ: TH1D	hchi2contr	 : 0 at: 0x7fdb67ad0af0
  OBJ: TH2D	hframe_LTs	 : 0 at: 0x7fdb60f92000
  OBJ: TH1D	hframe_Q2eps	 : 0 at: 0x7fdb3ff2c2e0
  OBJ: TH1D	hframe_GMp	 : 0 at: 0x7fdb3ff2f9a0
  OBJ: TH2D	hframe_RS	 : 0 at: 0x7fdb6043c000
  OBJ: TH2D	hframe_TPE	 : 0 at: 0x7fdb63b86000
  **OBJ: TH1F	gGMp_Ratio_newRC	 : 0 at: 0x7fdb3dda8e80**
  KEY: TGraphErrors	gGMp;1	
  KEY: TGraph	gGMpError;1	Graph
  KEY: TGraphErrors	gRp;1	Graph
  KEY: TGraph	gRpError;1	Graph
  KEY: TGraphErrors	gRp2;1	Graph
  KEY: TGraphErrors	gDataFitRatio_vs_Q2;1	
  KEY: TGraphErrors	gDataFitRatio_vs_EPS;1	
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_1;1	Q^{2} =  5.99 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_2;1	Q^{2} =  7.02 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_3;1	Q^{2} =  7.94 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_4;1	Q^{2} =  8.99 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_5;1	Q^{2} =  9.84 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_6;1	Q^{2} = 12.25 (GeV/c)^{2}
  KEY: TGraphErrors	sigmaR_vs_epsilon_box_7;1	Q^{2} = 15.72 (GeV/c)^{2}
  KEY: TGraphErrors	gRp2_LT;1	Graph
  KEY: TGraphErrors	gGMp_LT;1	Graph
  KEY: TGraphErrors	gRp_LT;1	Graph
  KEY: TMultiGraph	mgr_GM;1	
  KEY: TGraphErrors	gRp2_PT;1	#mu_{p}G_{E}^{p} / G_{M}^{p} = #mu_{p}(1 - #tau F_{2} / F_{1}) / (1 + F_{2} / F_{1})
  KEY: TGraphErrors	gDeltaTPE;1	Graph
  KEY: TGraphAsymmErrors	gRp_LTasym;1	Graph
  KEY: TGraph	gTension;1	
  KEY: TGraph	gConfidence;1	Graph
  KEY: TGraphErrors	GMp_Kirk;1	
  KEY: TGraphErrors	GMp_Rock;1	
  KEY: TGraphErrors	GMp_Sill;1	
  KEY: TGraphErrors	GMp_Christy;1	
  KEY: TGraphErrors	GMp_GMp12L;1	
  KEY: TGraphErrors	GMp_GMp12R;1	
  KEY: TGraphErrors	GMp_Andivahis_1;1	
  KEY: TGraphErrors	GMp_Andivahis_2;1	
  KEY: TGraphErrors	GMp_Walker;1	
  KEY: TH1D	hchi2contr;1	
  KEY: TGraphErrors	gsigR_PT_box1;1	Graph
  KEY: TGraphErrors	gsigR_PT_box2;1	Graph
  KEY: TGraphErrors	gsigR_PT_box3;1	Graph
  KEY: TGraphErrors	gsigR_PT_box4;1	Graph
  KEY: TGraphErrors	gsigR_PT_box5;1	Graph
  KEY: TGraphErrors	gsigR_PT_box6;1	Graph
  KEY: TGraphErrors	gsigR_PT_box7;1	Graph
  KEY: TGraph	gdRp2;1	
  **KEY: TGraphErrors	gGMp_Ratio_newRC;1**	
Canvas Name=c13 Title=c13 Option=
 TCanvas fXlowNDC=0 fYlowNDC=0 fWNDC=1 fHNDC=1 Name= c13 Title= c13 Option=
  OBJ: TList	TList	Doubly linked list : 0
   OBJ: TH2D	hframe_TPE	 : 0 at: 0x7fdb63b86000
   TLine  X1=0.000000 Y1=0.000000 X2=20.000000 Y2=0.000000
   OBJ: TGraphErrors	Graph	Graph : 0 at: 0x7fdb3ff39400
   OBJ: TGraphErrors	Graph	 : 0 at: 0x7fdb68287200
   OBJ: TLegend	TPave  	X1= 5.000000 Y1=0.060000 X2=18.000000 Y2=0.110000

Use a “Clone”:

I confirm that the clone method gets rid of the warning and prevents the creation of the extra histogram. Seems like it would probably be a good idea to fix the behavior of the copy constructor though…

Problem with copy constructor and assign operator will be fixed by the PR 7309

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.