Please, advise me on how to free memory from the created unsafe
C# struct
(s) using some standard C# toolset or how get I get the IntPtr
of those objects to use the default provided custom C library?
The problem details (UPD):
I create the C#
unsafe struct
and pass it to C dll that I can't changeTH_ExtractBimTemplate(ref createdStruct)
. The dll updates its content. And in addition to that, the dll saves the reference to the struct object inside of it in an internal list. Here is the struct definition:public unsafe struct BIM_Template { public ushort ImageSizeX; public ushort ImageSizeY; public fixed uint Mint[MAX_MINUTIAE_SIZE]; public uint Reserve; }
After the API call returns, I use the data in the struct populated by the C dll in my C# code.
I need to free the memory used by the struct and C . The dll has an API to do this,
TH_FreeMemory
.
For step #3 I need to pass the object reference (I presume IntPtr
) to C library or I need to Free the memory it was occupying with some C# instrument.
The Garbage Collection doesn't work even if there are no reference in my C# code to the object, I assume, because of the struct object reference is stored in the list in the dll that I don't control. When TH_FreeMemory
on the struct object is called, it removes it from the list and release the memory with delete
, but I can't generate the C# IntPtr
to pass it to the TH_FreeMemory
for that...
How can I do that - release the memory with just C# tools, ignoring the list dll or generate the IntPtr
for this struct?
The implementation details:
This is how I create and initialize it:
BIM_Template template = default;
var template = TH_ExtractBimTemplate(ref template)
Where TH_ExtractBimTemplate(...)
is the method that is pulled from the C dll in this way:
[DllImport("TemplateHelper.dll")]
private static extern int TH_ExtractBimTemplate(
ref BIM_Template out_template);
The TemplateHelper.dll
provides me a C method to release the memory - TH_FreeMemory
:
int WINAPI TH_FreeMemory( void *memblock, BIM_MemBlockType memblock_type )
This is how I plug it into C#
[DllImport("TemplateHelper.dll")]
private static extern int TH_FreeMemory(
IntPtr memblock, BIM_MemBlockType memblock_type
);
Current solutions I tried:
- I need
IntPtr
of the createdunsafe struct
(the template variable) but I don't know how to get it, to free allocated memory withTH_FreeMemory
dll method - I have tried to create a bunch of these
unsafe struct
type templates in the method that create them and return void, leaving no references to the created templates, but the garbage collector doesn't free memory. I assume that is, because of the object type isunsafe struct
. At least, I've waited for 40 minutes and memory wasn't released. - I have tried the approach below to release the memory with
Marshal.FreeHGlobal(IntPtr ptr)
but that doesn't reduce the amount of unmanaged memory used by the app as well here is the code:
[Fact]
public void TestDisposalIsCalledOnOutOfContext()
{
// Create templates
var templates = LoadTemplates(m, Output);
// Release the allocated memory using Marshal
templates.ForEach( t => MarshaFreeMemory(ref t));
// Wait
Thread.Sleep(new TimeSpan(hours: 1, 0, 0));
}
private static IntPtr MarshaFreeMemory(ref BIM_Template? template)
{
IntPtr ptr;
ptr = Marshal.AllocHGlobal(Marshal.SizeOf<BIM_Template>());
Marshal.StructureToPtr(template, ptr, true);
Marshal.FreeHGlobal(ptr);
return ptr;
}
private static List<BIM_Template?> LoadTemplates()
{
var templates = new List<BIM_Template?>();
for (int j = 0; j < 1000; j ) templates.Add(LoadTemplate());
return templates;
}
public static BIM_Template LoadTemplate()
{
BIM_Template template = default;
var template = TH_ExtractBimTemplate(ref template);
return template;
}
So, the question is how can I prevent these memory leaks and free memory from the created templates using some standard C# toolset or how get I get the IntPtr
of the template object to use the library?
CodePudding user response:
You don’t need to call TH_FreeMemory
. Your structure doesn’t have any pointers inside. In C , the Mint
field should be std::array<uint32_t, MAX_MINUTIAE_SIZE>
or an equivalent.
Your template
local variable is on the stack, it does not use any heap memory, and the stack memory will be freed automatically just before the LoadTemplate()
method returns.
if you wanna free the memory used by the list in TestDisposalIsCalledOnOutOfContext
, do this:
templates = null;
// Collect all generations of memory
GC.Collect();