Memory usage in TSE
by James Urquhart · in Torque Game Engine Advanced · 09/29/2006 (5:18 am) · 17 replies
Hi there,
Recently i noticed TSE seemed to be using up extortionate amounts of memory for seemingly simple scenes (100+mb), and decided to investigate where all the memory is being used up.
So far, here's what i found:
1) The first problem i noticed was that the "LangElement" struct in TSE (used to generate shaders) didn't have a virtual destructor defined. This meant that the destructor on various LangElement derivatives wasn't called (which isn't very good when shaders are being generated).
To solve this problem, i stuck this line on the end of the LangElement declaration:
2) I noticed in the memory allocation log certain allocations were defined as "Undetermined".
Some of these came from reallocations, which recreate memory blocks without filenames (e.g. in the StringTable).
To solve this little problem, i changed the following line in realloc():
3) After a while, my attention turned towards the DataChunker object's.
I noticed that "DataChunker memPool;" in the "ResDictionary" class wasn't even used, so i commented it out.
I also found that "Namespace::mAllocator" was only cleared after TSE was shut down - though this isn't really a problem unless one decides to restart the console system (i.e. you'd still have the list of namespace entries for the previous instance hanging about in memory).
For completeness, one can always modify NameSpace::shutdown as follows:
4) I noticed that just before the main script is run, "SimChunk::initChunkMappings();" is called. This seems to loop through the console class list, create an item, check if its derived from SimChunk, and then dispose of it.
Creating every class in the engine was sure to take time, so i devised an alternate method:
My general observations so far with the demo mod are:
* Before the main script is called, ~20mb is being used up.
* After the main script is run, an additional ~17mb is allocated.
* When one starts the demo mission, the memory usage skyrockets past the 100mb mark before the main GameConnection is created (perhaps caused by the Material's).
* Upon returning to the main gui, the memory usage rests at ~120mb
* When entering and leaving the demo mission, one can notice a gradual increase in memory usage when the mission is loaded.
All observations were taken from the Task Manager (yes, i know its not the most accurate thing to use). I am using a modified copy of TSE taken from yesterday's CVS.
I will add any further observations i find to this thread. Meanwhile, if anyone else has got anything to add, feel free to do so :)
Recently i noticed TSE seemed to be using up extortionate amounts of memory for seemingly simple scenes (100+mb), and decided to investigate where all the memory is being used up.
So far, here's what i found:
1) The first problem i noticed was that the "LangElement" struct in TSE (used to generate shaders) didn't have a virtual destructor defined. This meant that the destructor on various LangElement derivatives wasn't called (which isn't very good when shaders are being generated).
To solve this problem, i stuck this line on the end of the LangElement declaration:
virtual ~LangElement(){;}I also noticed after doing this the destructor for the "EchoOp" class was incorrect. It should be the following:EchoOp::~EchoOp()
{
delete [] /*(void*)*/mStatement;
}2) I noticed in the memory allocation log certain allocations were defined as "Undetermined".
Some of these came from reallocations, which recreate memory blocks without filenames (e.g. in the StringTable).
To solve this little problem, i changed the following line in realloc():
//void* ret = alloc(size, false, NULL, 0); // Bad void* ret = alloc(size, false, hdr->fileName, 0); // GoodOthers came from things such as DXDiagNVUtil, but I'm not exactly sure why this is the case. I also noticed that the resource manager was using dRealloc to create the mod path list.
3) After a while, my attention turned towards the DataChunker object's.
I noticed that "DataChunker memPool;" in the "ResDictionary" class wasn't even used, so i commented it out.
I also found that "Namespace::mAllocator" was only cleared after TSE was shut down - though this isn't really a problem unless one decides to restart the console system (i.e. you'd still have the list of namespace entries for the previous instance hanging about in memory).
For completeness, one can always modify NameSpace::shutdown as follows:
void Namespace::shutdown()
{
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
walk->clearEntries();
mAllocator.freeBlocks(); // Free namespaces & namespace entries
} 4) I noticed that just before the main script is run, "SimChunk::initChunkMappings();" is called. This seems to loop through the console class list, create an item, check if its derived from SimChunk, and then dispose of it.
Creating every class in the engine was sure to take time, so i devised an alternate method:
void SimChunk::initChunkMappings()
{
Con::printf("Initializing chunk mappings...");
SimChunk *simChunkInst = (SimChunk*)create("SimChunk");
for(AbstractClassRep *rep = AbstractClassRep::getClassList(); rep; rep = rep->getNextClass())
{
if (rep->isClass(simChunkInst->getStaticClassRep()))
{
SimChunk *chunk = (SimChunk*)rep->create();
Con::printf(" o '%s' maps to %s", chunk->getFourCCString(), chunk->getClassName());
FourCCToAcr * fcta = new FourCCToAcr();
fcta->fourCC = chunk->getFourCC();
fcta->acr = rep;
smFourCCList.push_back(fcta);
delete chunk;
}
}
delete simChunkInst;
// Also register the .chunk file format.
ResourceManager->registerExtension(".chunk", ChunkFile::constructChunkFile);
}My general observations so far with the demo mod are:
* Before the main script is called, ~20mb is being used up.
* After the main script is run, an additional ~17mb is allocated.
* When one starts the demo mission, the memory usage skyrockets past the 100mb mark before the main GameConnection is created (perhaps caused by the Material's).
* Upon returning to the main gui, the memory usage rests at ~120mb
* When entering and leaving the demo mission, one can notice a gradual increase in memory usage when the mission is loaded.
All observations were taken from the Task Manager (yes, i know its not the most accurate thing to use). I am using a modified copy of TSE taken from yesterday's CVS.
I will add any further observations i find to this thread. Meanwhile, if anyone else has got anything to add, feel free to do so :)
#2
Are you using the memory manager flagging functionality? These other fixes look great, THANK YOU for sharing them.
09/29/2006 (10:30 am)
James,Are you using the memory manager flagging functionality? These other fixes look great, THANK YOU for sharing them.
#3
5) I noticed some paths seemed to be sticking around after the mission was quit. It seems that whilst the server tells the client to clear path's, the server doesn't seem to bother calling the "clearServerPaths" console function to sort out itself. In addition, the client doesn't call "clearClientPaths" in case somehow the message doesn't get through.
The solution of course is to add, say, a call to "clearServerPaths" on the server when the mission has ended, and also a similar call to "clearClientPaths" on the client when they have disconnected.
6) The infamous ParticleEmitter strikes again. Sometimes the game will create them, but never delete them. This problem is made even more annoying by the fact that it doesn't seem to function quite the same as other SceneObject's (e.g. you might be lucky if you find it present in the client/server containers).
I ended up doing all sorts of funky stuff. e.g. adding the particle emitter to the server container as well as the client, but i couldn't seem to get anything to work. That is, until i discovered that there was a ParticleEmitter whose onAdd() failed. Then i came to this bit in shapeImage.cpp:
I moved stuff around so that i used a regular ParticleEmitter* pointer instead of the SimObjectPtr, like so:
7) There seems to be a few other issues with the shader generator, notably with the fog code. I've not had time to invesigate this further.
@Ben:
I am indeed using the memory manager flagging functionality.
09/29/2006 (1:12 pm)
Some more points of interest:5) I noticed some paths seemed to be sticking around after the mission was quit. It seems that whilst the server tells the client to clear path's, the server doesn't seem to bother calling the "clearServerPaths" console function to sort out itself. In addition, the client doesn't call "clearClientPaths" in case somehow the message doesn't get through.
The solution of course is to add, say, a call to "clearServerPaths" on the server when the mission has ended, and also a similar call to "clearClientPaths" on the client when they have disconnected.
6) The infamous ParticleEmitter strikes again. Sometimes the game will create them, but never delete them. This problem is made even more annoying by the fact that it doesn't seem to function quite the same as other SceneObject's (e.g. you might be lucky if you find it present in the client/server containers).
I ended up doing all sorts of funky stuff. e.g. adding the particle emitter to the server container as well as the client, but i couldn't seem to get anything to work. That is, until i discovered that there was a ParticleEmitter whose onAdd() failed. Then i came to this bit in shapeImage.cpp:
bem->emitter = new ParticleEmitter;
bem->emitter->onNewDataBlock(state.emitter);
if( !bem->emitter->registerObject() )
delete bem->emitter;When it reached the delete line, for some reason the destructor on the ParticleEmitter wasn't called.I moved stuff around so that i used a regular ParticleEmitter* pointer instead of the SimObjectPtr, like so:
ParticleEmitter *emitter = new ParticleEmitter;
emitter->onNewDataBlock(state.emitter);
if( !emitter->registerObject() ) {
delete emitter;
emitter = NULL;
}
bem->emitter = emitter;But i still encountered problems, until i noticed this line in the ParticleEmitter declaration:~ParticleEmitter();Which probably should be:
virtual ~ParticleEmitter();I also changed similar lines in the parent class declaration's, and eventually, the problem was solved :)
7) There seems to be a few other issues with the shader generator, notably with the fog code. I've not had time to invesigate this further.
@Ben:
I am indeed using the memory manager flagging functionality.
#4
09/29/2006 (1:19 pm)
Another area you might want to look at is fonts and possibly even gui profile loading/unloading. There seems to be some weird interaction there that I think is causing a memory leak.
#5
I think my fixes got them all, so no need for you to spend time looking for them. Keep focus on the other areas - damn great work you do here!!!
09/30/2006 (12:01 am)
@James - I've recoded some of the emitter stuff and send to Brian R - there is more than what you have found, and the deletion process for the emitters is error prone. So there will be generated hundreds of emitters that are not cleared out.I think my fixes got them all, so no need for you to spend time looking for them. Keep focus on the other areas - damn great work you do here!!!
#6
7) It seems that memory is left over by the shader generator when generating shaders. The end of the "#ifdef GEN_NEW_SHADERS" block in ShaderGen::generateShader should thus look like this:
8) There are a few vector array's that have not been associated with specific file's, making it a bit difficult to see where they are being used. e.g. in the Interior class:
As of now, i've still got about 83 mysterious vector's with allocated memory still about after the mission has ended.
9) I devised a quick method which would let me clear out texture's used by Material's. The changes are as follows.
In the CubemapData declaration, add:
In the Material class declaration, add:
Then in material.cpp, you can add the following definitions:
And in cubemapData.cpp:
Finally, you need to call ::clearMaterialStages, so i just put it in the reInitMaterials ConsoleFunction for the time being:
EDIT:I also noticed that MaterialList is a bit funky handling textures, so i changed it around a bit:
The interior code seems to crap up, so when i reload the mission after a call to this modified reInitMaterials, the orc base interior is white, whilst dts shapes are more or less fine. Yikes! (i am still unsure what is happening here)
Sadly, i did not notice much, if any decrease in memory usage (like, 3mb) when using this code, so i guess i must be missing something somewhere else. However this code should still be useful to anyone who wants to reload texture's in Materials :)
Speaking of purgeResources, it seems to be defined twice - once in game.cpp, and the other in resManager.cpp. Yikes!
09/30/2006 (3:16 am)
More on my previous point :7) It seems that memory is left over by the shader generator when generating shaders. The end of the "#ifdef GEN_NEW_SHADERS" block in ShaderGen::generateShader should thus look like this:
ShaderGenManager::closeNewShaderStream( s ); LangElement::deleteElements(); // <-- +Need to free elements generated by the pixel shader features #endifI still noticed a few more things in the Shader generator still hanging about created by ShaderGen::init(), but thankfully everything is cleared in ShaderGen::uninit(), when torque quit's or a new shader is generated, so its not too much of an issue.
8) There are a few vector array's that have not been associated with specific file's, making it a bit difficult to see where they are being used. e.g. in the Interior class:
// Add to the bottom of Interior::Interior VECTOR_SET_ASSOCIATION(mVehicleWindings); VECTOR_SET_ASSOCIATION(mVehicleWindingIndices); VECTOR_SET_ASSOCIATION(mZoneRNList); VECTOR_SET_ASSOCIATION(mZoneReflectRNList); VECTOR_SET_ASSOCIATION(mReflectPlanes); VECTOR_SET_ASSOCIATION(mMatInstCleanupList); VECTOR_SET_ASSOCIATION(mPointVisibility); VECTOR_SET_ASSOCIATION(mLightDirMapsTex); VECTOR_SET_ASSOCIATION(mLightDirMaps); VECTOR_SET_ASSOCIATION(surfaceZones);(Though the only interior leftovers seem to be the static sgZoneRects, sgZoneRenderInfo, and zoneStack)
As of now, i've still got about 83 mysterious vector's with allocated memory still about after the mission has ended.
9) I devised a quick method which would let me clear out texture's used by Material's. The changes are as follows.
In the CubemapData declaration, add:
void destroyMap();
In the Material class declaration, add:
static void clearMaterialStages(); virtual void clearStageData();
Then in material.cpp, you can add the following definitions:
void Material::clearStageData()
{
if (!hasSetStageData) return;
hasSetStageData = false;
for( U32 i=0; i<MAX_STAGES; i++ )
{
for (U32 f=0; f<GFXShaderFeatureData::NumFeatures; f++)
stages[i].tex[f] = NULL;
}
if( mCubemapData )
{
mCubemapData->destroyMap();
stages[0].cubemap = NULL;
}
}
void Material::clearMaterialStages()
{
SimSet *set = getMaterialSet();
if (set)
{
for (SimSet::iterator itr = set->begin(); itr != set->end(); itr++)
{
Material *mat = static_cast<Material*>(*itr);
mat->clearStageData();
}
}
}EDIT: I would also suggest adding a call to clearStageData() in Material::onRemove().And in cubemapData.cpp:
void CubemapData::destroyMap()
{
if (cubemap)
{
delete cubemap;
cubemap = NULL;
for( U32 i=0; i<6; i++ )
{
if (cubeFace[i])
{
cubeFace[i] = NULL;
}
}
}
}Finally, you need to call ::clearMaterialStages, so i just put it in the reInitMaterials ConsoleFunction for the time being:
ConsoleFunction( reInitMaterials, void, 1, 1, "" )
{
Material::clearMaterialStages();
MatInstance::reInitInstances();
}EDIT:I also noticed that MaterialList is a bit funky handling textures, so i changed it around a bit:
void MaterialList::unload()
{
// ...
for(S32 i=0; i < mMaterials.size(); i++) {
mMaterials[i] = NULL; // replaces mMaterials[i].~GFXTexHandle();
}
// ...
}
void MaterialList::free()
{
// ...
for(S32 i=0; i < mMaterials.size(); i++)
{
if(mMaterialNames[i])
delete [] mMaterialNames[i];
mMaterials[i] = NULL; // replaces commented out mMaterials[i].~GFXTexHandle();
}
// ... (note that mMaterials.setSize() will destruct texture handle's)
}The interior code seems to crap up, so when i reload the mission after a call to this modified reInitMaterials, the orc base interior is white, whilst dts shapes are more or less fine. Yikes! (i am still unsure what is happening here)
Sadly, i did not notice much, if any decrease in memory usage (like, 3mb) when using this code, so i guess i must be missing something somewhere else. However this code should still be useful to anyone who wants to reload texture's in Materials :)
Speaking of purgeResources, it seems to be defined twice - once in game.cpp, and the other in resManager.cpp. Yikes!
#7
09/30/2006 (3:43 am)
James, did you try pulling objects from the mission to see if the memory was tied to any one object or object type?
#8
Not yet, i will have to check that.
It seems most of the additional memory allocations (i.e. those i checked that appeared after two mission loads) come from either the console code, data chunker, or texture / bitmap code.
Here's a new one for you.
10) It seems that GFont manages a list of texture handle's, which don't seem to be cleared properly, which could potentially lead to references being kept.
Add to GFont::~GFont
Which should clear them. It would also be a good idea to add this in "GFont::importStrip":
I also noticed a reference to GFont::mCharInfoList in my dump, though i think thats ok.
09/30/2006 (4:13 am)
@John:Not yet, i will have to check that.
It seems most of the additional memory allocations (i.e. those i checked that appeared after two mission loads) come from either the console code, data chunker, or texture / bitmap code.
Here's a new one for you.
10) It seems that GFont manages a list of texture handle's, which don't seem to be cleared properly, which could potentially lead to references being kept.
Add to GFont::~GFont
for (i=0; i<mTextureSheets.size(); i++)
{
// Either should probably do
mTextureSheets[i] = NULL;
destructInPlace(&mTextureSheets[i]);
}Which should clear them. It would also be a good idea to add this in "GFont::importStrip":
// Wipe our texture sheets.
mCurSheet = mCurX = mCurY = 0;
// ++ Clear Sheets ++
for (U32 i=0; i<mTextureSheets.size(); i++)
{
mTextureSheets[i] = NULL;
destructInPlace(&mTextureSheets[i]);
}
// ++ End Clear Sheets ++
mTextureSheets.clear();I also noticed a reference to GFont::mCharInfoList in my dump, though i think thats ok.
#9
I decided to go along with your suggestion and see if any object's were being kept around after the mission was shut down, and i appear to have found something interesting...
I made a function to record all script object's allocated in the game. I made it compare any previous record, to determine if any new object's were present.
I then ran the function twice, once before the mission, and once after it had ended:
And then i decided to try again:
I checked the id's, and it appears that these objects are being constantly recreated, and never cleaned up.
In essence, an overhead of 24 objects is being added each time the mission is loaded.
I've not had time to investigate further, but i'd guess that the MaterialSet needs clearing out, provided of course that these CustomMaterial's are correctly being added to it in the first place.
As for the MissionInfo, i thought that was part of the mission?
09/30/2006 (6:42 am)
@John,I decided to go along with your suggestion and see if any object's were being kept around after the mission was shut down, and i appear to have found something interesting...
I made a function to record all script object's allocated in the game. I made it compare any previous record, to determine if any new object's were present.
I then ran the function twice, once before the mission, and once after it had ended:
2001 -> CustomMaterial(DynCubeSphereFallback) 2002 -> CustomMaterial(DynCubeSphere) 2003 -> CustomMaterial(TendrilFallback) 2004 -> CustomMaterial(Tendril) 2005 -> CustomMaterial(OuterKnotFallback) 2006 -> CustomMaterial(OuterKnot) 2007 -> CustomMaterial(BlobSurface1Fallback) 2008 -> CustomMaterial(BlobSurface1) 2009 -> CustomMaterial(BlobSurface2Fallback) 2010 -> CustomMaterial(BlobSurface2) 2011 -> CustomMaterial(TwoFallback) 2012 -> CustomMaterial(Two) 2013 -> CustomMaterial(SixBumpFallbackPass2) 2014 -> CustomMaterial(SixBumpFallback) 2015 -> CustomMaterial(SixBump) 2016 -> CustomMaterial(Blank) 2017 -> CustomMaterial(AtlasDynamicLightingMaterial) 2018 -> CustomMaterial(AtlasMaterial) 2019 -> CustomMaterial(AtlasBlender20Material) 2020 -> CustomMaterial(TerrainMaterialDynamicLighting) 2021 -> CustomMaterial(TerrainMaterial) 2022 -> CustomMaterial(TerrainBlenderPS20Material) 2023 -> CustomMaterial(TerrainBlenderPS11AMaterial) 2024 -> CustomMaterial(TerrainBlenderPS11BMaterial) 2027 -> ScriptObject(MissionInfo)
And then i decided to try again:
2473 -> CustomMaterial(DynCubeSphereFallback) 2474 -> CustomMaterial(DynCubeSphere) 2475 -> CustomMaterial(TendrilFallback) 2476 -> CustomMaterial(Tendril) 2477 -> CustomMaterial(OuterKnotFallback) 2478 -> CustomMaterial(OuterKnot) 2479 -> CustomMaterial(BlobSurface1Fallback) 2480 -> CustomMaterial(BlobSurface1) 2481 -> CustomMaterial(BlobSurface2Fallback) 2482 -> CustomMaterial(BlobSurface2) 2483 -> CustomMaterial(TwoFallback) 2484 -> CustomMaterial(Two) 2485 -> CustomMaterial(SixBumpFallbackPass2) 2486 -> CustomMaterial(SixBumpFallback) 2487 -> CustomMaterial(SixBump) 2488 -> CustomMaterial(Blank) 2489 -> CustomMaterial(AtlasDynamicLightingMaterial) 2490 -> CustomMaterial(AtlasMaterial) 2491 -> CustomMaterial(AtlasBlender20Material) 2492 -> CustomMaterial(TerrainMaterialDynamicLighting) 2493 -> CustomMaterial(TerrainMaterial) 2494 -> CustomMaterial(TerrainBlenderPS20Material) 2495 -> CustomMaterial(TerrainBlenderPS11AMaterial) 2496 -> CustomMaterial(TerrainBlenderPS11BMaterial) 2499 -> ScriptObject(MissionInfo)
I checked the id's, and it appears that these objects are being constantly recreated, and never cleaned up.
In essence, an overhead of 24 objects is being added each time the mission is loaded.
I've not had time to investigate further, but i'd guess that the MaterialSet needs clearing out, provided of course that these CustomMaterial's are correctly being added to it in the first place.
As for the MissionInfo, i thought that was part of the mission?
#10
09/30/2006 (6:57 am)
This is all greek to me, but if it helps TSE run better: my thanks to you, James!
#11
09/30/2006 (10:36 am)
Great work, James - I've alerted Brian to this thread so we ought to see uptake into TSE sometime soon. :)
#12
09/30/2006 (11:49 am)
Excellent work James, I knew about some of this stuff already, but there are some things I hadn't seen before. Thanks, I'll get all this in as soon as I can.
#13
No problem. Just thought i'd hop to and nail these problems down ;)
Regarding the last problem i mentioned, the MissionInfo object can be removed by adding a call to "clearLoadInfo()" to the endMission script function. This is also where i placed the "clearServerPaths()" call to solve problem 5).
EDIT: i had another look, and it seems that CustomMaterial had a custom setStageData implementation. So naturally, i implemented an equivalent clearStageData implementation:
Sadly, even though i try and clear the Materials and whatnot out, i am still noticing that there appears to be a gradual increase in GFXTextureObject's being allocated (around 20 each reload, as observed by calling dumpExtantTOS()). A pity they don't actually tell me where they have been allocated or assigned =/
Although on a plus side i noticed i seem to have fixed the problem i had with the Interior's i had when called reInitMaterials() - it seems if i delete every material from the MaterialSet, it re-processes them correctly (maybe its that call to setStageData(), though that should happen in MatInstance::init too...
Anyhow, good luck - i think i'm going to try and make something before i find any more bugs :)
09/30/2006 (1:38 pm)
Brian,No problem. Just thought i'd hop to and nail these problems down ;)
Regarding the last problem i mentioned, the MissionInfo object can be removed by adding a call to "clearLoadInfo()" to the endMission script function. This is also where i placed the "clearServerPaths()" call to solve problem 5).
EDIT: i had another look, and it seems that CustomMaterial had a custom setStageData implementation. So naturally, i implemented an equivalent clearStageData implementation:
void CustomMaterial::clearStageData()
{
Material::clearStageData();
for (U32 i=0; i<MAX_TEX_PER_PASS; i++)
{
tex[i] = NULL;
}
if ( mShaderData && mShaderData->shader )
{
mShaderData->destroyShader();
}
}(NOTE: Should probably also be called in the destructor)Sadly, even though i try and clear the Materials and whatnot out, i am still noticing that there appears to be a gradual increase in GFXTextureObject's being allocated (around 20 each reload, as observed by calling dumpExtantTOS()). A pity they don't actually tell me where they have been allocated or assigned =/
Although on a plus side i noticed i seem to have fixed the problem i had with the Interior's i had when called reInitMaterials() - it seems if i delete every material from the MaterialSet, it re-processes them correctly (maybe its that call to setStageData(), though that should happen in MatInstance::init too...
Anyhow, good luck - i think i'm going to try and make something before i find any more bugs :)
#14
09/30/2006 (3:57 pm)
It should give you the profiler path to the allocation.
#15
That is a good point - however, the profiler path has a tendancy of being very vague :)
09/30/2006 (4:04 pm)
@Ben:That is a good point - however, the profiler path has a tendancy of being very vague :)
#16
09/30/2006 (4:09 pm)
You can also extend the memory manager alloc flagging stuff to track TO allocations and give you line/file numbers...
#17
09/30/2006 (4:09 pm)
Or add more profiler blocks :P
Associate James Urquhart
At the end of the clientCmdSetGameGui function, add:
if ($LEAKTEST !$= "") { warn("Test: Disconnecting"); schedule(2000, 0, disconnect); }At the end of the disconnect function, add:
if ($LEAKTEST !$= "") { warn("Test: Loading feature mission"); schedule(2000, 0, loadFeatureMission); }Then one can type in the console:
Provided $LEAKTEST is set, when you press the "Feature Walkthrough" button on the demo mod the mission will be constantly reloaded. After a while, you should notice TSE's memory usage in the Task Manager gradually increase. For example, i got mine up to 530mb!
Evidently further investigation is required to identify the root cause of this memory leak.