Question about memory leak

Take this function:

void function()
{
    string clusters[3] = {"33", "35", "37"};
    TCanvas debug_canvas("debug_canvas", "debug canvas");
    debug_canvas.Divide(2,2);
    for (int i=0; i<3; ++i)
    {
	debug_canvas.cd(i+1);
	stringstream histo_name;
	histo_name << "heta" << clusters[i];
	TH1F* histo = static_cast<TH1F*>(f->Get(histo_name.str().c_str()));
	histo->Draw();
    }
    canvas.SaveAs("debug.png");
}

Am I generating a memory leak? I mean: who delete the 3 histos? When the canvas is automatically deleted are the histo drawn inside also deleted? It’s quite boring because the only (ugly) solution it’s to store the three TH1F* inside a vector during the first loop and at the end (after the SaveAs) call delete over all of them. Or not?

[quote=“wiso”]Take this function:

Am I generating a memory leak? I mean: who delete the 3 histos? When the canvas is automatically deleted are the histo drawn inside also deleted? It’s quite boring because the only (ugly) solution it’s to store the three TH1F* inside a vector during the first loop and at the end (after the SaveAs) call delete over all of them. Or not?
[/quote]

You omitted the part of program declaring ‘f’, but still … If it’s a file (TFile) you open somewhere, by default it’s an owner of a histogram (this behavior can be modified).

[quote=“tpochep”][quote=“wiso”]Take this function:

Am I generating a memory leak? I mean: who delete the 3 histos? When the canvas is automatically deleted are the histo drawn inside also deleted? It’s quite boring because the only (ugly) solution it’s to store the three TH1F* inside a vector during the first loop and at the end (after the SaveAs) call delete over all of them. Or not?
[/quote]

You omitted the part of program declaring ‘f’, but still … If it’s a file (TFile) you open somewhere, by default it’s an owner of a histogram (this behavior can be modified).[/quote]

yes, the TFile is declared before, but the point is that I need to open 1000+ histograms, and my program require 3Gb+. After saving the plot of the histogram on the png I don’t need it anymore. What the best way (in this case) to delete it? I can’t use a smart pointer for example because when the smart pointer goes out of scope (at every loop) the histogram is deleted and so also its plot.

Do you mean, you want to generate 1000+ png files? Or do you want to divide canvas into 1000 sub-pads?
Do you want to reduce memory consumption somehow or what?
It would be good if you can clarify this - the answer (or code sample) depends on what you exactly want.

[quote=“tpochep”][quote=“wiso”]
yes, the TFile is declared before, but the point is that I need to open 1000+ histograms, and my program require 3Gb+. After saving the plot of the histogram on the png I don’t need it anymore. What the best way (in this case) to delete it?
[/quote]

Do you mean, you want to generate 1000+ png files? Or do you want to divide canvas into 1000 sub-pads?
Do you want to reduce memory consumption somehow or what?
It would be good if you can clarify this - the answer (or code sample) depends on what you exactly want.[/quote]

The first one, I need to generate 1000+ png files.

  1. load some histograms with TFile::Get
  2. do some fits
  3. plot these histograms in a TCanvas
  4. save the TCanvas as png
  5. redo with other similar histograms

I want to reduce memory consumption.

[quote=“wiso”]
The first one, I need to generate 1000+ png files.

  1. load some histograms with TFile::Get
  2. do some fits
  3. plot these histograms in a TCanvas
  4. save the TCanvas as png
  5. redo with other similar histograms

I want to reduce memory consumption.[/quote]

  1. You know how to do.
  2. The same.
  3. Well, you did this already in you macro (hist->Draw).
  4. You call SaveAs in a loop, with correct file name (like a histo name, but with “.png”).
  5. This I do not understand: in principle, 1000 TH1D objects is not too huge amount of memory. They do not reqiure 3Gb. But still, after you call SaveAs in a loop, you can delete the hist.

Something like this (I was compiling this macro to make it faster, and use it in a batch mode):

#include <TCanvas.h>
#include <TString.h>
#include <TFile.h>
#include <TH1.h>


void read()
{
    TFile f("hist.root", "READ");
    TCanvas c;
    c.cd();
    for(int i = 0; i < 10000; ++i)
    {
        TH1 * hist = (TH1 *)f.Get(TString::Format("hist%d", i).Data());
        if(hist) {
            hist->Draw();
            c.SaveAs(TString::Format("hist%d.png", i).Data());
            delete hist;
        }
    }
}

Hmm, I have to check that the histo is removed from list of primitives in TCanvas - looks like it’s done in ~TObject, so, you can delete hist this way.

[quote=“tpochep”][quote=“wiso”]
The first one, I need to generate 1000+ png files.

  1. load some histograms with TFile::Get
  2. do some fits
  3. plot these histograms in a TCanvas
  4. save the TCanvas as png
  5. redo with other similar histograms

I want to reduce memory consumption.[/quote]

  1. You know how to do.
  2. The same.
  3. Well, you did this already in you macro (hist->Draw).
  4. You call SaveAs in a loop, with correct file name (like a histo name, but with “.png”).
  5. This I do not understand: in principle, 1000 TH1D objects is not too huge amount of memory. They do not reqiure 3Gb. But still, after you call SaveAs in a loop, you can delete the hist.

Something like this (I was compiling this macro to make it faster, and use it in a batch mode):

#include <TCanvas.h>
#include <TString.h>
#include <TFile.h>
#include <TH1.h>


void read()
{
    TFile f("hist.root", "READ");
    TCanvas c;
    c.cd();
    for(int i = 0; i < 10000; ++i)
    {
        TH1 * hist = (TH1 *)f.Get(TString::Format("hist%d", i).Data());
        if(hist) {
            hist->Draw();
            c.SaveAs(TString::Format("hist%d.png", i).Data());
            delete hist;
        }
    }
}

Hmm, I have to check that the histo is removed from list of primitives in TCanvas - looks like it’s done in ~TObject, so, you can delete hist this way.[/quote]

as I said I need to plot these histograms so something like:
void read()
{
TFile f(“hist.root”, “READ”);
TCanvas c;
c.cd();
for(int i = 0; i < 10000; ++i)
for(int j=0; j<10; ++j)
{
TH1 * hist = (TH1 *)f.Get(TString::Format(“hist%d%d”, i, j).Data());
if(hist) {
hist->Draw(j==0 ? “” : “same”);
}
}
c.SaveAs(TString::Format(“hist%d.png”, i).Data());
}
}
[/code]

So I need another loop on j to delete the 10 histograms, and I need also a vector to store the pointers to the object that I want to delete. This is boring and error prone. For example: does it exist a mechanism that when the canvas goes out of scope it deleted everythings plotted inside of it?

[quote=“wiso”]

void read()
{
    TFile f("hist.root", "READ");
    TCanvas c;
    c.cd();
    for(int i = 0; i < 10000; ++i)
    for(int j=0; j<10; ++j)
    {
        TH1 * hist = (TH1 *)f.Get(TString::Format("hist%d%d", i, j).Data());
        if(hist) {
            hist->Draw(j==0 ? "" : "same");
                  }
    }
    c.SaveAs(TString::Format("hist%d.png", i).Data());
    }
}

So I need another loop on j to delete the 10 histograms, and I need also a vector to store the pointers to the object that I want to delete. This is boring and error prone. For example: does it exist a mechanism that when the canvas goes out of scope it deleted everythings plotted inside of it?[/quote]

Yes, you can do, for example:

void read()
{
    TFile f("hist.root", "READ");
    for(int i = 0; i < 10000; ++i)
    {
         TCanvas c;
         c.cd();
         for(int j=0; j<10; ++j)
         {
             TH1 * hist = (TH1 *)f.Get(TString::Format("hist%d%d", i, j).Data());
             if (hist) {
                hist->SetBit(TObject::kMustCleanup);//check, may be, kCanDelete.
                hist->Draw(j==0 ? "" : "same");
             }
         }
         c.SaveAs(TString::Format("hist%d.png", i).Data());
    }
}

Hi,

You can also request the canvas to delete the histograms via:histo->SetBit(kCanDelete);

Cheers,
Philippe.

[quote=“pcanal”]Hi,

You can also request the canvas to delete the histograms via:histo->SetBit(kCanDelete);

Cheers,
Philippe.[/quote]

Thank you, this it what I need.