I am working on this high frequency production system. There is a C# / CLI layer which calls into a C++ library. What we are observing is that managed objects are going into generation 2 of the garabage collector and getting 'stuck'. Eventually the C# applications grind to a halt as RAM runs out. These managed objects are local objects and should have a very short lifetime. Also they are only referenced once. The C# applications are having to call .Dispose() on all their objects that hold native resources to ensure everything is forcefully deleted. We have quite a few objects so this isn't ideal and from an API perspective is messy. The CLI looks like this:
Field::~Field()
{
if(m_pField != NULL)
{
delete m_pField;
m_pField = NULL;
}
System::GC::SuppressFinalize(this);
}
Field::!Field()
{
if(m_pField != NULL)
{
delete m_pField;
}
}
Can anyone think why these short lived objects never seem to be collected and free the memory?
The problem is unmanaged objects don't count toward the "memory pressure" value that the GC uses to decide when to do a garbage collection.
One thing you can do is use GC.AddMemoryPressure(
to let the GC know that there is a large unmanaged object associated with your managed wrapper.
Field::Field()
{
//... Other stuff
if(m_pField != NULL)
{
m_lSizeOfField = GetSizeOfField(m_pField);
System::GC::AddMemoryPressure(m_lSizeOfField);
}
}
Field::~Field()
{
//If you had managed objects you would call "delete" here on them.
//delete m_managedData;
//In C++/CLI if you have unmanged resources just have the dispose method
// call the finalizer. It is cleaner and easier to maintain.
// You can't do this in C#
this->!Field();
//No need to add this next line, C++/CLI does it for you.
//System::GC::SuppressFinalize(this);
}
Field::!Field()
{
if(m_pField != NULL)
{
delete m_pField;
m_pField = NULL;
System::GC::RemoveMemoryPressure(m_lSizeOfField);
}
}