Reducing memory usage when using TClonesArray with TTree

Hello, rooter.
I am a student who is writing a Geant4 simulation program with ROOT framework.
I am using TClonesArray to store each step information of the simulation, with step class which I made.
To save this information for each event, I build a tree in a TFile, which has a branch for the TClonesArray of my step class.
However, the memory usage is too large so that the memory of my computer runs out easily.

Of course, I clean all of the objects at the end of an event, which I created during the processing of steps. So I expected the memory usage will reduce when the objects cleaned. But, It does not so.

I think there are some memory leaks in the TTree and TClonesArray. So, I performed some experiments to confirm my postulate. The step of the experiment is as follows:

  1. Create a .root file and build a TTree in the file.
  2. Then, make a TClonesArray which stores TObjString class and register this array as a branch.
  3. Fill the array with test string for a big number (I filled 10000000 times)
  4. Fill the tree
  5. Delete an object of the TClonesArray.
  6. Delete an object of the TTree.

The result is that the memory usage did not reduce even the tree has been destroyed (after delete fTree;)
If I do not use the TTree and TFile, it seems that the memory is freed when the object of TClonesArray is destroyed.

Here is my source code for the experiment.

#include "TClonesArray.h"
#include "TTree.h"
#include "TFile.h"
#include "TObjString.h"

#include <iostream>

using namespace std;

int main()
{
  Int_t entries = 10000000;
  TClonesArray* arr = new TClonesArray("TObjString",10000000);
  TTree* fTree;
  TFile* fOutput;
  TObjString targ("test_string");

  fOutput = new TFile("testin.root","NEW");

  fTree = new TTree("dummy","dummy");

  fTree->Branch("dummy",&arr);

  for(int i = 0; i<entries; i++){
  ¦ new ((*arr)[i]) TObjString(targ);
  }

  cout << "End of loop" << endl;
  cout << "filling the tree" << endl;
  fTree->Fill();
  cout << "filling done. " << endl;
  cout << "Before destruction. " << endl;
  cin.get();

  delete arr;

  cout << "Destruction done. " << endl;
  cin.get();
  fOutput->Close();
  delete fOutput;

  cout << "File Closed. " << endl;
  cin.get();
}

Be aware:
a) TString (and thus TObjString) can allocate (if the string exceeds the limit for short string optimization, i.e. 15 (?) chars on 64 bit machines)
b) on my machine, I see the mem usage dropping between the cin calls. But note that it isn’t guaranteed that freed memory will be given back to the operating system. It can also be reused in your program.
c) you use “new” instead of “recreate” - therefore be careful when re-running your program
d) read the notes:

This is not the case for TObjString, there is no Clear function. And TString::Clear does NOT free the memory but keeps it!

I was surprised about this:

Of course, I clean all of the objects at the end of an event, which I created during the processing of steps. So I expected the memory usage will reduce when the objects cleaned.

Isn’t the idea of a TClonesArray that you don’t do that but reuse all your objects instead of new/deleting them for every event?

Thanks for your kind reply!!

Let me answer your question.

a) Sorry… I could not understand your reply exactly… TString(or TObjString) can allocate… what?

A code shown in my question is just for my experiment to simulate memory usage in my simulation.
In the simulation, my class for the step information contains three TString objects and this would contain a string of which length is about 5~30 characters.

b) Of course, that is true. The memory usage drops as cin proceeds. However, the memory usage before the beginning of loop is not same as after destroying of the file class.
On my machine, my program shown above uses about 450MB of system memory before a loop then, the program uses about 1.17GB of memory after it reached “Before destruction”. After the destruction, the program occupies about 1.02GB of memory. Finally, the memory usage is 600MB after closing the file.
It seems that the difference between before loop and after the destruction of file object is small(about 150MB) but, a difference becomes bigger by increasing total number of entry.
In my opinion, the difference should be zero because all of the containers have been destroyed after the statement of “delete fOutput;”.

c) Thanks for your kindful advice!

d) Actually, I have read this note but, I could not completely understand internal mechanism of TClonesArray. It seems to initialize an object on a space of system memory by using placement new, which is already allocated. However, what is Clear(“C”) does?
As I know, the option “C” calls the Clear() function of each class to reset an objects on the memory space. What I need is that my program should shrink its allocated memory when the end of events. Does the option perform this action?

Suprised) As I said, my program should return its memory to the system after saving every information in an event to an output file.
Thus, even if my program uses a memory of 5GB during an event, the program should deallocate the memory after the event. To implement this, I cleaned all of an object.(although the implementation failed) If there is a way to reduce the memory usage without delete, please let me know the way!

Question) The TString class allocates memory in its inner action. I think it must be deallocated to avoid the memory leak. It is managed automatically??

P.S. Sorry for my poor English. I am not a native English speaker so there might be ambiguous or misleading words. If you can not understand my reply, please ask about it.

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