Memory leak in TMessage::ReadObjectAny?

Dear all,

I have found a memory leak in my program and I don’t see where it can possibly come from. I identified the line causing it (see valgrind output at the end of the message) but can’t figure out what I am doing wrong. The leak happens when I use TMessage::ReadObjectAny to deserialize a MonitorObject retrieved from a db. A MonitorObject is basically an encapsulation of something else, in our case a TH1F.

I would be extremely glad if someone could point me to what I am doing wrong here. Do I missuse the TMessage ? or did I possibly forget something in the MonitorObject class ? Or is it something in TMessage ?

Thanks in advance for your help,
See below for details
Barth

The code snipet creating the leak is here :

[snip]

 unsigned char* blob = 0;
 Long_t blobSize;
 TMessage mess;

 // for each row found, update the corresponding MonitorObject
 while (fStatement->NextResultRow()) {
  // retrieve the data
  Bool_t r = fStatement->GetBinary(0, (void*&) blob, blobSize); 
  string name = fStatement->GetString(1);
  // we use a TMessage to deserialize the MonitorObject
  mess.SetBuffer(blob, blobSize, kFALSE);
  mess.SetReadMode();
  mess.Reset();
  MonitorObject* mo = (MonitorObject*) mess.ReadObjectAny(mess.GetClass()); // <--- Memory leak
  delete mo;
 }

[snip]

The memory leak is at the line indicated by the comment.

And here is the valgrind comment :

==12212== 12,801,888 bytes in 11 blocks are possibly lost in loss record 458 of 458 ==12212== at 0x4005301: operator new[](unsigned int) (vg_replace_malloc.c:268) ==12212== by 0x45E2ADA: TArrayF::Set(int) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x45E25D6: TArrayF::Streamer(TBuffer&) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x48905E6: TArrayF::StreamerNVirtual(TBuffer&) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x485613E: G__G__Cont_98_0_28(G__value*, char const*, G__param*, int) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x4B4A8CC: Cint::G__CallFunc::Execute(void*) (in /local/root-5-24-patch/lib/libCint.so.5.24) ==12212== by 0x4637E05: TCint::CallFunc_Exec(void*, void*) const (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x461EADD: TMethodCall::Execute(void*) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x462AE03: TStreamerBase::ReadBuffer(TBuffer&, char*) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x52AA2E8: int TStreamerInfo::ReadBuffer<char**>(TBuffer&, char** const&, int, int, int, int) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x51F12C3: TBufferFile::ReadClassBuffer(TClass const*, void*, TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x55F01B3: TH1F::Streamer(TBuffer&) (in /local/root-5-24-patch/lib/libHist.so.5.24) ==12212== by 0x46059FB: TClass::Streamer(void*, TBuffer&, TClass const*) const (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x51EF3D7: TBufferFile::ReadObjectAny(TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x51EDE24: TBufferFile::ReadFastArray(void**, TClass const*, int, bool, TMemberStreamer*, TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x52A8168: int TStreamerInfo::ReadBuffer<char**>(TBuffer&, char** const&, int, int, int, int) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x51F1088: TBufferFile::ReadClassBuffer(TClass const*, void*, int, unsigned int, unsigned int, TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x58161E0: TPaveStats::Streamer(TBuffer&) (in /local/root-5-24-patch/lib/libGraf.so.5.24) ==12212== by 0x46059FB: TClass::Streamer(void*, TBuffer&, TClass const*) const (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x51EF3D7: TBufferFile::ReadObjectAny(TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x45F0661: TBuffer& operator>><TObject>(TBuffer&, TObject*&) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x45F4FB3: TList::Streamer(TBuffer&) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x46059FB: TClass::Streamer(void*, TBuffer&, TClass const*) const (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x51EDE6B: TBufferFile::ReadFastArray(void**, TClass const*, int, bool, TMemberStreamer*, TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x52A8168: int TStreamerInfo::ReadBuffer<char**>(TBuffer&, char** const&, int, int, int, int) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x51F1088: TBufferFile::ReadClassBuffer(TClass const*, void*, int, unsigned int, unsigned int, TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x5541E09: TH1::Streamer(TBuffer&) (in /local/root-5-24-patch/lib/libHist.so.5.24) ==12212== by 0x56EBF52: TH1::StreamerNVirtual(TBuffer&) (in /local/root-5-24-patch/lib/libHist.so.5.24) ==12212== by 0x560A7BA: G__G__Hist_96_0_221(G__value*, char const*, G__param*, int) (in /local/root-5-24-patch/lib/libHist.so.5.24) ==12212== by 0x4B4A8CC: Cint::G__CallFunc::Execute(void*) (in /local/root-5-24-patch/lib/libCint.so.5.24) ==12212== by 0x4637E05: TCint::CallFunc_Exec(void*, void*) const (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x461EADD: TMethodCall::Execute(void*) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x462AE03: TStreamerBase::ReadBuffer(TBuffer&, char*) (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x52AA2E8: int TStreamerInfo::ReadBuffer<char**>(TBuffer&, char** const&, int, int, int, int) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x51F12C3: TBufferFile::ReadClassBuffer(TClass const*, void*, TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x55F01B3: TH1F::Streamer(TBuffer&) (in /local/root-5-24-patch/lib/libHist.so.5.24) ==12212== by 0x52AA2B6: int TStreamerInfo::ReadBuffer<char**>(TBuffer&, char** const&, int, int, int, int) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x51F12C3: TBufferFile::ReadClassBuffer(TClass const*, void*, TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x40F6A03: amore::core::MonitorObjectHisto<TH1F>::Streamer(TBuffer&) (CoreDict.cpp:2821) ==12212== by 0x40DAADD: G__CoreDict_537_0_28(G__value*, char const*, G__param*, int) (CoreDict.cpp:4616) ==12212== by 0x4B4A8CC: Cint::G__CallFunc::Execute(void*) (in /local/root-5-24-patch/lib/libCint.so.5.24) ==12212== by 0x4637E05: TCint::CallFunc_Exec(void*, void*) const (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x4605A87: TClass::Streamer(void*, TBuffer&, TClass const*) const (in /local/root-5-24-patch/lib/libCore.so.5.24) ==12212== by 0x51EF3D7: TBufferFile::ReadObjectAny(TClass const*) (in /local/root-5-24-patch/lib/libRIO.so.5.24) ==12212== by 0x4040479: amore::subscriber::PoolConnection::Process(amore::subscriber::SubscriptionProxy*) (TMessage.h:75) ==12212== by 0x40325E8: amore::subscriber::Subscriber::Receive(std::_Rb_tree_const_iterator<std::pair<std::string const, amore::subscriber::SubscriptionProxy*> > const&) (stl_tree.h:250) ==12212== by 0x4032838: amore::subscriber::Subscriber::Receive() (Subscriber.cpp:229) ==12212== by 0x403286F: amore::subscriber::Subscriber::Update() (Subscriber.cpp:171) ==12212== by 0x4032A80: amore::subscriber::Subscriber::MonitorCycle() (Subscriber.cpp:186) ==12212== by 0x4032ACE: amore::subscriber::Subscriber::RunLoop() (Subscriber.cpp:150)

Oh, and by the way, if someone knows another way of deserializing my object after I retrieve it from the database, I would be very glad to hear about it !

Thanks
Barth

Answering to myself to add more information.

MonitorObject is an abstract class. Various sub-classes exist depending on the type of the object encapsulated : MonitorObjectTObject, MonitorObjectHisto, MonitorObjectHisto2D, MonitorObjectString and MonitorObjectGraph.

MonitorObjectHisto[2D] is templated to indicate the type of the histogram : TH1F, TH1D…

MonitorObjectTObject encapsulate any TObject and therefore doesn’t provide the interface to specific methods of the histograms.

The memory leak exists only with MonitorObjectHisto and MonitorObjectHisto2D. Even encapsulating a TH1F within an MonitorObjectTObject doesn’t create a leak !

So, do you think it could be related to the fact that we have this hierarchy where some sub-classes are templated ?

Thanks for any help,
Barth

[quote]The memory leak exists only with MonitorObjectHisto and MonitorObjectHisto2D. Even encapsulating a TH1F within an MonitorObjectTObject doesn’t create a leak ! [/quote]What is the difference between MonitorObjectHisto and MonitorObjectTObject?

Philippe

Hi,

Coming back to this issue I had. As usual in such cases, the problem doesn’t rely where you think it does.

Making the history short, the process publishing data into the database was publishing objects twice too big (see below). Then the process getting the data out of the database was deserializing with a TMessage the object and freeing it in the end, but freeing only the real size although the reserved memory was twice bigger.

Now, why was the objects twice too big ?
Well, replacing a call to Draw() by DrawClone() solved the problem. But I don’t understand why. Any clue ?

Barth