ROOT internal memory management

This is a general question about CERN ROOT internal memory management.

I am experiencing some strange behaviour in my ROOT analysis macros whereby I do not seem to have the expected number of histograms with a certain name.

Rather than post a specific question about this, I would like to ask a question about how the internal ROOT memory management works.

My understanding is has something to do with whether an object inherits from TNamed, but I might be wrong.

The first question to ask is where is the documentation which relates to understanding this. I have (probably) already read it, but I ask this first regardless to check.

Other than that, the other question I would like to ask is what does “TH1::Clone()” or “TH2::Clone()” do in regards to this internal memory management, both in the cases where no argument is given and when an argument is given.

Hi,
only some objects are registered with ROOT’s own memory management/garbage collection system (not all objects that inherit form TNamed). Histograms, by default, are owned by the current TDirectory (i.e. gDirectory, e.g. the last TFile opened) and Clone does not change that. The most up-to-date documentation is probably at https://root.cern/manual/object_ownership.

I don’t think the Clone method does anything special w.r.t. ownership. Something that might make things “interesting” is that, if I understand correctly, you have multiple objects with the same name. I don’t know how that might interact with ROOT’s internal memory management, (@pcanal or @Axel might).

It you provide a small reproducer of the behavior you see I/we might be able to help further.
My personal suggestion: in most cases the simplest thing to do is to detach your histograms from ROOT’s memory management calling TH1::AddDirectory(false) and use standard C++ memory management techniques, e.g. std::unique_ptr.

Cheers,
Enrico

I probably do have multiple objects with the same name, and yes it would be helpful to understand what ROOT does in such cases.

Why are histograms associated with the last opened TFile? If I remember correctly, this means if that file is closed, then the associated histogram objects are deleted.

I can’t provide you with a MWE because at the moment I don’t know for sure if something is “wrong” as such.

Is there any way to know whether an objects will be associated to the last opened file or gROOT? It seems like TCanvas are always associated to gROOT and TH1, TH2 are always associated to gDirectory. Is that the case? In which case, an asside question is how is one able to tell which kind of objects are associated to which?

Thanks for the quick reply.

It has occured to me that there are two specific cases that I can draw your attention to. (I just give one for now.)

Firstly in regards to drawing… I have some output canvas with multiple pads, and on one of those pads I do, for example…

Call TH1->Draw("AXIS") first. This is so that the pad sets the axis range, defined by ->SetRangeUser or ->SetMaximum. I am not sure if both or just one are required.

Then I draw a TLine on the pad.

Finally, draw the histogram with option “SAME”.

In this case, presumably if I intend to use the histogram elsewhere I need to Clone() before drawing. (ie: If I go on to use the histogram in the analysis after drawing it, then the drawing output breaks. Such as changing the bin contents/errors. Hopefully you understand my point here, not sure if it’s clear?)

I’m aware DrawClone() exists. I don’t know if this is something I should use instead. When I tried playing with it, this didn’t seem to work.

That will probably do for now I don’t want to throw pages of text at the thread.

A slightly different point. (Sorry to spam the thread further.)

I appear to be able to use gROOT->FindObject() to retrieve pointers to my histograms, despite the fact that they should be owned by a TFile, aka, a TDirectory object.

Is this behaviour expected? It appears to conflict with the documentation unless I am misinterpreting it.

Hi @Birdsall,
if I understand correctly the open questions are:

Is there any way to know whether an objects will be associated to the last opened file or gROOT? how is one able to tell which kind of objects are associated to which?

and

I appear to be able to use gROOT->FindObject() to retrieve pointers to my histograms, despite the fact that they should be owned by a TFile, aka, a TDirectory object. Is this behaviour expected?

From my side I can say ownership is one thing, it has to do with who will delete what. Being “findable” via gROOT->FindObject() is another (iow, just because an object can be found with gROOT->FindObject(), it doesn’t mean that gROOT owns it).

We need @pcanal or @Axel for more in-depth answers.

Cheers,
Enrico

Yes. gROOT has a hierarchy of items that has been registered and thus can be searched. This includes the list of Canvases and the list of Files. The search is recursive. Thus if an histogram belong to a file that is registered (the default behavior) then it can be found. so being found by gROOT->FindObject does not indicated direct ownership.

Is there any way to know whether an objects will be associated to the last opened file or gROOT?

TTree, TH*, TGraph2D and TEntryList will be associated with the “current directory” at the time, i.e. the directory pointed to by “gDirectory” (note gROOT “is a” directory for this purpose). (and “technically” the answer to your question is checking the value of gDirectory->GetList()->FindObject( my_pointer ))

What happens if I use TFile->Get() to load a histogram from file. Does the last opened TFile own this object or does the TFile associated with the call to Get() own the object?

Presumably this means that if the TFile goes out of scope or is otherwise deleted then any pointers to histograms become invalid also?

I changed my code to use TH1::AddDirectory(false) and TH2::AddDirectory(false), and it appears to be behaving more as I would expect, but I have not implemented any cleanup at the end of execution yet.

Finally I would still be interested to know about the behaviour of Clone(), particuarly in the case where no argument is provided. And DrawClone also.

When reading an histogram, it gets associated with the file it comes from independently of what the current directory is.

Presumably this means that if the TFile goes out of scope or is otherwise deleted then any pointers to histograms become invalid also?

That is correct. Call hist->SetDirectory(nullptr) to detach it from the TFile and take full ownership) or indeed use TH1::AddDirectory(false)

Finally I would still be interested to know about the behaviour of Clone(), particuarly in the case where no argument is provided. And DrawClone also.

The new histogram (when allowed by TH1::AddDirectory) is attached to the current directory.

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