Problem 2077

Summary: Memory Leakage on G4ParticleHPContAngularPar::cacheInit()
Product: Geant4 Reporter: Roy <admin>
Component: runAssignee: Pedro.Arce
Status: RESOLVED DUPLICATE    
Severity: normal CC: Koichi.Murakami
Priority: P4    
Version: 10.4   
Hardware: All   
OS: All   

Description Roy 2018-08-17 21:13:17 CEST
I am using the version 10.4, but this code is present also in other revision

The object created in https://github.com/Geant4/geant4/blob/master/source/processes/hadronic/models/particle_hp/include/G4ParticleHPContAngularPar.hh#L199

Is never deleted... So after a very high number of event the mem leakage became big.

I checked in the destructor of the G4Cache<V>::~G4Cache() and enable the #ifdef G4VERBOSE to report if the lock was unavailable, but nothing was written.

And also checked that G4CacheReference<V>::Destroy but logic is not very clear to me at the moment if the whole cached is deleted , or... just a single element (I see no iteration)

I will try and check more code to see If I am able to provide a fix, but for now I can only provide a stack trace of the leakage

30K iteration 
Direct leak of 310080 byte(s) in 6460 object(s) allocated from:
    #0 0x7f9b7994bcb0 in operator new(unsigned long) (/usr/lib64/libasan.so.4+0xddcb0)
    #1 0x7f9b77418f5e in G4ParticleHPContAngularPar::cacheInit() /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/include/G4ParticleHPContAngularPar.hh:199
    #2 0x7f9b77412bc7 in G4ParticleHPContAngularPar::G4ParticleHPContAngularPar(G4ParticleDefinition*) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPContAngularPar.cc:63
    #3 0x7f9b7741c562 in G4ParticleHPContEnergyAngular::Sample(double, double, double) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPContEnergyAngular.cc:84
    #4 0x7f9b773fab81 in G4ParticleHPProduct::Sample(double, int) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPProduct.cc:124
    #5 0x7f9b774291b7 in G4ParticleHPEnAngCorrelation::Sample(double) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPEnAngCorrelation.cc:195
    #6 0x7f9b7740ad6f in G4ParticleHPCaptureFS::ApplyYourself(G4HadProjectile const&) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPCaptureFS.cc:90
    #7 0x7f9b77410c2f in G4ParticleHPChannel::ApplyYourself(G4HadProjectile const&, int) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPChannel.cc:308
    #8 0x7f9b77406c3d in G4ParticleHPCapture::ApplyYourself(G4HadProjectile const&, G4Nucleus&) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPCapture.cc:141
    #9 0x7f9b76fb75d9 in G4HadronicProcess::PostStepDoIt(G4Track const&, G4Step const&) /home/ryzen2/geant4/source/processes/hadronic/management/src/G4HadronicProcess.cc:344
    #10 0x7f9b784b36c4 in G4SteppingManager::InvokePSDIP(unsigned long) /home/ryzen2/geant4/source/tracking/src/G4SteppingManager2.cc:562
    #11 0x7f9b784b354e in G4SteppingManager::InvokePostStepDoItProcs() /home/ryzen2/geant4/source/tracking/src/G4SteppingManager2.cc:534

If instead I run with less iteration (10K) is similar with

Direct leak of 106512 byte(s) in 2219 object(s) allocated from:
    #0 0x7f011051fcb0 in operator new(unsigned long) (/usr/lib64/libasan.so.4+0xddcb0)
    #1 0x7f010dfecf5e in G4ParticleHPContAngularPar::cacheInit() /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/include/G4ParticleHPContAngularPar.hh:199
    #2 0x7f010dfe6bc7 in G4ParticleHPContAngularPar::G4ParticleHPContAngularPar(G4ParticleDefinition*) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPContAngularPar.cc:63
    #3 0x7f010dff0562 in G4ParticleHPContEnergyAngular::Sample(double, double, double) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPContEnergyAngular.cc:84
    #4 0x7f010dfceb81 in G4ParticleHPProduct::Sample(double, int) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPProduct.cc:124
    #5 0x7f010dffd1b7 in G4ParticleHPEnAngCorrelation::Sample(double) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPEnAngCorrelation.cc:195
    #6 0x7f010dfded6f in G4ParticleHPCaptureFS::ApplyYourself(G4HadProjectile const&) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPCaptureFS.cc:90
    #7 0x7f010dfe4c2f in G4ParticleHPChannel::ApplyYourself(G4HadProjectile const&, int) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPChannel.cc:308
    #8 0x7f010dfdac3d in G4ParticleHPCapture::ApplyYourself(G4HadProjectile const&, G4Nucleus&) /home/ryzen2/geant4/source/processes/hadronic/models/particle_hp/src/G4ParticleHPCapture.cc:141
    #9 0x7f010db8b5d9 in G4HadronicProcess::PostStepDoIt(G4Track const&, G4Step const&) /home/ryzen2/geant4/source/processes/hadronic/management/src/G4HadronicProcess.cc:344
    #10 0x7f010f0876c4 in G4SteppingManager::InvokePSDIP(unsigned long) /home/ryzen2/geant4/source/tracking/src/G4SteppingManager2.cc:562
    #11 0x7f010f08754e in G4SteppingManager::InvokePostStepDoItProcs() /home/ryzen2/geant4/source/tracking/src/G4SteppingManager2.cc:534
Comment 1 Roy 2018-08-18 01:23:25 CEST
So yes I can confirm is a bug somewhere in the actual logic, the comment in the destructor here is quite clear https://github.com/Geant4/geant4/blob/6aa23be5171b125c3363b5a4cfa00a57e524598b/source/global/management/include/G4CacheDetails.hh#L252

// Ownership is for client
// delete (*cache)[id];

So during the destruction phase the vector is cleaned, but NOT the object inside... which are responsability of the owner of the cache.

Now I will check if is ok to delete during the destructor this cache, or if this value has been passed around.
Comment 2 Roy 2018-08-18 01:49:33 CEST
I am now 99% sure that yes is possible to clean element in the cache in the destructor of G4ParticleHPContAngularPar, the content is not passed anywhere after the end of life of the obj.


I will now mod my local copy, and let run a quite long simulation.
Comment 3 Roy 2018-08-18 16:38:42 CEST
Basically the problem arises from https://github.com/Geant4/geant4/blob/6aa23be5171b125c3363b5a4cfa00a57e524598b/source/global/management/include/G4CacheDetails.hh#L227

In case that the value to be placed in the Cache is a ptr, a temporary object is created, stored and than LOST because later will be overwritten...

If instead the object is not a ptr, the temp one is created, and than later properly destroyed when is overwritten.

I also checked adding

https://en.cppreference.com/w/cpp/types/is_pointer

static_assert (std::is_pointer<V>::value, "do not use with PTR");

To see where else a ptr is used and is in several place. 

Proposed fix is to 
template<class V>
void G4Cache<V>::Put( const V& val ) const {
	if constexpr(std::is_pointer<V>::value) {
		delete GetCache();
	}
	GetCache() = val;
}

But sadly is cached a ptr of G4VelocityTable which is a singleton, so ... no public destructor... 

So I think we just have to change the leaking class to not store a ptr...
Comment 4 kurasige 2018-08-27 11:50:15 CEST
Hi, Roy

 Thank you for reporting a bug with detailed investigation.
 And sorry for my late response.

 I have a question on your report.
 In the G4ParticleHPContAngularPar class, toBeCached struct is defined for G4Cache template.
http://www-geant4.kek.jp/lxr/source/processes/hadronic/models/particle_hp/include/G4ParticleHPContAngularPar.hh#L49 class 
 It contains three G4double and two pointers to G4ReactionProduct.    
 http://www-geant4.kek.jp/lxr/source/processes/hadronic/util/include/G4ReactionProduct.hh 

 You said " But sadly is cached a ptr of G4VelocityTable which is a singleton, so ... no public destructor... "
 G4VelocityTable is defined as a static member of G4Track. But, G4ReactionProduct has the pointer to G4ParticleDefinition not to G4Track.

 Could you explain how G4VelocityTable is related to this problem ?

 And I'd explain memory allocation of a singleton object. It is allocated automatically at the beginning of running the program, and is deleted at the end of running the program. Its constructor and destructor are invoked automatically and are not called by other classes. So, no public constructor and destructor are provided.
   
 
 Thank you and Cheers,
			Hisaya
Comment 5 Roy 2018-08-27 12:17:35 CEST
Hy Hisaya.

The problem with the singleton is that the proposed fix with the "static if" can not be applied, because ... it can not call the destructor for this object!

So ... is not leaking the Singleton, but is blocking the cache to ... work with just a single small fix...
Comment 6 kurasige 2018-08-30 08:50:25 CEST
I forward this problem to Makoto, who is responsible for G4Cache
Comment 7 Gabriele Cosmo 2018-11-15 15:47:15 CET
Problem is already fixed in the development version and will be included in next releases.

*** This problem has been marked as a duplicate of problem 2026 ***