Home > OS >  How to get IntPtr of c# unsafe struct to free its memory initialized in c dll
How to get IntPtr of c# unsafe struct to free its memory initialized in c dll

Time:05-29

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):

  1. I create the C# unsafe struct and pass it to C dll that I can't change TH_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; 
    }
    
  2. After the API call returns, I use the data in the struct populated by the C dll in my C# code.

  3. 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 created unsafe struct (the template variable) but I don't know how to get it, to free allocated memory with TH_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 is unsafe 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();
  • Related