Re: [ROOT] Memory leak when using TClonesArray::ExpandCreate

From: Frankland John (frankland@ganil.fr)
Date: Sun Jul 20 2003 - 18:32:18 MEST


Hello Rene

Rene Brun wrote:

>Hi John,
>
>You are not drawing the right conclusion from your observation
>with MyNuc::GetNbObj. Let me explain.
>
>The TClonesArray is based on the standard C++ "new with placement".
>When calling new(a[i]) myclass(), the following happens:
> -if a[i] is null, an object of myclass is allocated space and the 
>myclass
>constructor is called.
> - if a[i] is not null, your myclass constructor is called. No need to 
>allocate space (time consuming). The object is simply initialized by the
>statements in your constructor, overwriting the values of the data 
>members
>created by a previous call to the constructor. The address of the object
>is the one previously stored at a[i] (new with placement).
>In your case your class MyNuc records only the number of calls
>to your myclass constructor. It does not record the number of times
>a new object has been allocated.
>
>
>  
>
In order to see this happening, I modified the MyNuc class as in the 
attachment.
I added a static TList to which I add the "this" pointer every time the 
ctor is called, only if
the object pointed to is not already in the list. However, despite 
protecting all possible
cases of pointer abuse, when I compile and run the test.C script 
attached (.L libPhysics.so,
.L MyNuc.cxx+, then .L test.C+) it ends up in a segmentation fault:

root [0] .L libPhysics.so
root [1] .L MyNuc.cxx+
Info in <TUnixSystem::ACLiC>: creating shared library 
/home/john/lib//home/john/ClonesTests/./MyNuc_cxx.so
root [2] .L test.C+
root [3] test()
 ++ Calling default ctor ++
Calling AddToObjList...
AddToObjList............
Creating object list....
done
fNb_Objects=1, size of list=1
 ++ Calling default ctor ++
Calling AddToObjList...
AddToObjList............
done
 ++ Calling default ctor ++
Calling AddToObjList...
AddToObjList............
done
 ++ Calling default ctor ++
Calling AddToObjList...
AddToObjList............
done
 ++ Calling default ctor ++
Calling AddToObjList...
AddToObjList............
done
 ++ Calling default ctor ++
Calling AddToObjList...
AddToObjList............
done
fNb_Objects=6, size of list=6
fNb_Objects=6, size of list=6
 ++ Calling default ctor ++
Calling AddToObjList...
AddToObjList............

 *** Break *** segmentation violation
 Generating stack trace...
/usr/bin/c++filt: unknown demangling style `gnu-new-abi'

I can't see why ! Can somebody please help me ?
My last CVS update/compile was July 14th, on Linux RH8 with gcc3.2.

Thanks a lot
John

-- 

ganil logo <http://www.ganil.fr>
John D. Frankland <mailto:frankland@ganil.fr>
Beam Coordinator
GANIL
B.P. 55027
14076 CAEN Cedex 05

*tel:* +33 (0)231454628
*fax:* +33 (0)231454665







#ifndef __MyNuc_H
#define __MyNuc_H

#include "TLorentzVector.h"

class MyNuc : public TLorentzVector
{
			UChar_t fZ;
			UChar_t fA;
			static Int_t fNb_Objects;
			static TList* fObjList;
			void AddToObjList(TObject*);
			
	public:
			MyNuc();
			MyNuc(const MyNuc &);
			MyNuc(int z, int a);
			virtual ~MyNuc();
			
			void SetZ(int z){fZ=(UChar_t)z;}
			void SetA(int a){fA=(UChar_t)a;}
			Int_t GetZ() const;
			Int_t GetA() const;
			Int_t GetNbObj(Option_t *opt="");
			void SetPxPyPz(Float_t px, Float_t py, Float_t pz);
			void Clear(Option_t *opt="");
			
			ClassDef(MyNuc,1) // Just for tests
};

#endif


#include "MyNuc.h"
#include <Riostream.h>

ClassImp(MyNuc)
		
//__________________________________________________________________
//MyNuc
//For testing TClonesarray behaviour
//
		
Int_t MyNuc::fNb_Objects=0;
TList *MyNuc::fObjList=0;

MyNuc::MyNuc()
{
	cout << " ++ Calling default ctor ++ " << endl;
	fZ = fA = 0;
	fNb_Objects++;
	cout << "Calling AddToObjList..." << endl;
	AddToObjList(this);
}

void MyNuc::AddToObjList(TObject* obj)
{
	//Add pointer to object to static list if the pointer is not already in the list
	cout << "AddToObjList............" << endl;
	if(!fObjList) {
		cout << "Creating object list...." << endl;
		fObjList=new TList;
	}
	if(obj){
		if(!fObjList->FindObject(obj)) fObjList->Add(obj);
	} else {
		cout << "(the 'this' pointer is NULL)........."  << endl;
	}
	cout << "done" << endl;
}

MyNuc::MyNuc(int z, int a)
{
	fZ = (UChar_t)z;
	fA = (UChar_t)a;
	fNb_Objects++;
	AddToObjList(this);
}

MyNuc::MyNuc(const MyNuc &obj)
{
	fZ = obj.GetZ();
	fA = obj.GetA();
	fNb_Objects++;
	AddToObjList(this);
}

MyNuc::~MyNuc()
{
	fNb_Objects--;
	if(!fNb_Objects) delete fObjList;
}

Int_t MyNuc::GetZ() const
{
	return (Int_t)fZ;
}

Int_t MyNuc::GetA() const
{
	return (Int_t)fA;
}

Int_t MyNuc::GetNbObj(Option_t *opt)
{
	if(strcmp(opt,"")) cout << "fNb_Objects=" << fNb_Objects << ", size of list=" << fObjList->GetSize() << endl;
	return fNb_Objects;
}

void MyNuc::Clear(const Option_t *opt)
{
	TLorentzVector::Clear(opt);
	fZ=fA=0;
}

void MyNuc::SetPxPyPz(Float_t px, Float_t py, Float_t pz)
{
	Float_t mass = 931.5*GetA();
	TLorentzVector::SetXYZM(px,py,pz,mass);
}


#include "MyNuc.h"
#include "TClonesArray.h"

void test()
{	
	MyNuc a;
	a.GetNbObj("print");
	
	TClonesArray tca("MyNuc", 50);
	
	tca.ExpandCreate(5);
	a.GetNbObj("print");
	tca.Clear("C");
	
	tca.ExpandCreate(3);
	a.GetNbObj("print");
	tca.Clear("C");
	
	tca.ExpandCreate(5);
	a.GetNbObj("print");
	tca.Clear("C");	
}



This archive was generated by hypermail 2b29 : Thu Jan 01 2004 - 17:50:13 MET