问题
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?
回答1:
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);
}
}
来源:https://stackoverflow.com/questions/40111289/cli-native-objects-getting-stuck-in-gen2-and-not-garbage-collected