Memory cleanup on closing TGTransientFrame

I have recently started writing code for a GUI using ROOT. For this, I am creating a few TGTransientFrame objects for the user to edit a few simple parameters and then the user closes these configuration windows, which can later be reopened when necessary. For some reason, however, the “DeleteWindow()” or “CloseWindow()” isn’t cleaning up all memory usage in my code. If I keep the GUI open, and open the TGTransientFrame for parameter setups and close it again a couple of times, I can see memory usage for the root process rise by a couple of megabytes, which is really bad considering that I meant this GUI to be kept open and the parameters reconfigured as many times as needed.

I’ve tried “ReallyDelete()”, “delete this”, and a couple of other combinations. I’ve tried deleting the widgets in the window also. A few combinations lead to segfaults (accessing previously deleted objects), and all the others I tried still present rising memory use after opening+closing this TGTransientFrame using, say, TGTransientFrame::DeleteWindow().

Is there something I’m doing wrong/forgetting? I have attached code for one of the configuration windows, if maybe taking a look will help identifying my problem. Thanks for helping! :slight_smile:
CTP_correlations.C (7.55 KB)

Hi,

In your code, a lot of widgets are created and not added to any parent frame (and then cannot be deleted). So you have to take care of their cleanup. For example, try to do this:

[code]CorrelationFrame::~CorrelationFrame()
{
// Delete window - destructor
for(int i1 = 0; i1<24; i1++){
for(int j1 = 0; j1<i1+1; j1++) {
delete Correlations[i1][j1];
}
delete Text_InputA[ i1 ];
delete Text_InputB[ i1 ];
}
delete Text_1;
delete Text_ParTitle;
delete Text_Threshold;
delete Text_CorrelationLimit;
CorrelationMainFrame->CloseWindow();
}

void CorrelationFrame::DoExit(){
for(int i1 = 0; i1<24; i1++){
for(int j1 = 0; j1<i1; j1++) {
if(Correlations[i1][j1]->IsOn()) { guiGlobals->SetCorrelation(i1,j1,1); }
if(!Correlations[i1][j1]->IsOn()) { guiGlobals->SetCorrelation(i1,j1,0); }
}
}
guiGlobals->SetCorrelationLimit( NumberEntry_CorrelationLimit->GetNumber() );
guiGlobals->SetThreshold( NumberEntry_Threshold->GetIntNumber() );
delete this;
}
[/code]
You can enable the object statistics in ROOT by setting the “Root.ObjectStat” value to 1 in $ROOTSYS/etc/system.rootrc (or in your own $HOME/.rootrc), and then call gObjectTable->Print(). This gives this kind of table:

[code]root [4] gObjectTable->Print();

Object statistics
class cnt on heap size total size heap size

================================================================================

TRootGuiFactory 1 1 28 28 28

ROOT::TSchemaRule 9 9 120 1080 1080

TVirtualX 1 1 84 84 84

TTimer 2 1 68 136 68

TBenchmark 1 1 52 52 52

TList 1765 1764 44 77660 77616

TGFontPool 1 1 32 32 32

TImagePalette 2 2 36 72 72

TObjectTable 1 1 24 24 24

TROOT 1 0 304 304 0

TPluginManager 1 1 24 24 24

TFileHandler 2 2 44 88 88

TObject 106 106 12 1272 1272

TStreamerInfo 5 5 108 540 540

THashTable 31 31 40 1240 1240

TClassTable 1 1 12 12 12

ROOT::TSchemaRuleSet 4 4 80 320 320

TGFrame 1 1 112 112 112

TGLayoutHints 1 1 48 48 48

TGResourcePool 1 1 200 200 200

TGFont 6 6 1388 8328 8328

TRandom3 1 1 2532 2532 2532

THashList 20 20 48 960 960

TGuiFactory 1 1 28 28 28

TProcessID 1 1 36 36 36

TObjString 810 810 20 16200 16200

TEnv 2 2 28 56 56

TEnvRec 2842 2842 44 125048 125048

TClass 76 76 208 15808 15808

TQClass 28 28 224 6272 6272

TFolder 19 19 36 684 684

TRint 1 1 164 164 164

TGGCPool 1 1 24 24 24

TNamed 111 111 28 3108 3108

TMap 1 0 28 28 0

TMessageHandler 1 1 72 72 72

TCint 1 1 260 260 260

TPair 783 783 20 15660 15660

TGLabel 4 4 176 704 704

TGDNDManager 1 1 100 100 100

TObjArray 145 145 40 5800 5800

TGMimeTypes 1 1 32 32 32

TOrdCollection 8 8 44 352 352

TSignalHandler 1 1 44 44 44

TBits 1 1 24 24 24

TMethod 1046 1046 76 79496 79496

TGGC 12 12 128 1536 1536

TGWin32 1 1 264 264 264

TWinNTSystem 1 1 632 632 632

TStopwatch 1 0 72 72 0

TExMap 1 1 24 24 24

TGTextLayout 4 4 32 128 128

TColor 344 344 60 20640 20640

TGPicturePool 1 1 28 28 28

TDataType 737 737 52 38324 38324

TMethodArg 2 2 40 80 80

TStyle 5 5 824 4120 4120

TPluginHandler 18 18 76 1368 1368

TSystemDirectory 1 1 44 44 44

TGClient 1 1 124 124 124

TBaseClass 51 51 76 3876 3876

TMethodCall 4 4 60 240 240

TProcessUUID 1 1 44 44 44


Total: 9034 9029 9776 436692 436176

================================================================================
[/code]
Then you can compare tables after several calls, to see if objects have not been deleted.
You should also try to compile your code (.L CTP_correlations.C+) to see if your code contains errors (it actually does)

Cheers, Bertrand.

This worked! I really liked the “ObjectTable->Print();” hint, that was particularly helpful! I have implemented the proper cleanup and now I guess there are no more memory leaks, everything is behaving as it should.

As for compiling the code, indeed… I get problems with that, have to be more careful. I’ll look into them. The actual “correlation” to which this refers is in another part of the code with a rather “painful” double-for-loop, meaning I think running it in CINT without compiling and creating the “.so” works but I’ve heard it will run much faster when running the “.so” compiled version, is that right? I want to check how that works (CINT+.so, never done that) so I was actually thinking about trying to compile at least a couple of the “speed-bottleneck” modules in the GUI. Still need root.exe and CINT for drawing Canvases, so this wouldn’t be “standalone” C++ programming…

Thank you very much for your help! :smiley:

Hi,

You’re welcome. And yes, using ACLiC has several advantages. It allows to check the validity of your code (as the compiler is more “strict” than Cint) and it allows to gain performance in heavy/deep level loops.

Cheers, Bertrand.