Memory leak using pInvoke

±

±I?@aI!iac????!j

Hi there,

C++ declaration:

void __stdcall VfwDecoder_GetOutputBitmapInfoHeader(HANDLE hVfwDecoder,
BITMAPINFOHEADER** ppBmh)
{
CVideoDecompress *pVideoDecompress = (CVideoDecompress*)hVfwDecoder;

if (pVideoDecompress != NULL )
*ppBmh = pVideoDecompress->GetOutputBitmapInfoHeader();
}

C# declaration:

[DllImport("VfwDecoder.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr VfwDecoder_DecompressNative(IntPtr hVfwDecoder,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.U1, SizeParamIndex = 2)] byte[]
CompressedData, uint dwSize);

Using:

BITMAPINFOHEADER bmpHeader = new BITMAPINFOHEADER();
VfwDecoderLib.VfwDecoder_GetOutputBitmapInfoHeader(m_hVfwDecoder, ref
bmpHeader);

When I using this code, the program is memory leak as the virtual memory is
growing. I know bmpHeader is not necessary to new BITMAPINFOHEADER() since
the native C++ function return the BITMAPINFOHEADER pointer to the caller.
But from my understanding, C# will garbarge collect the unused
BITMAPINFOHEADER object and prevent memory leak. Could anyone tell me why
there is memory leak?

Thanks a lot.
 
N

not_a_commie

The CLR won't garbage collect until it needs to. You should see the
memory usage climb for some time before stabilizing. Can you change
your declaration to use the 'out' keyword rather than a 'ref' keyword?
 
E

eseaflower

Unfortunatley I don't have a solution to the OPs problem, but I have a
similar problem and have done some troubleshooting on it. I'm in way over my
head here so please don't flame me if I state the obvious.
I have written a very small test program.
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace leakapp {
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal class DataContainer {
public Int32 m_arrayBindIndex = 12;
}

class Program {

static void Main(string[] args) {
Console.WriteLine("Begin...");
Console.ReadLine();
DataContainer ctx = new DataContainer();
long count = 100000;
for (long q = 0; q < 5; q++) {
for (long i = 0; i < count; i++) {
LeakClass(ref ctx);
}
Console.WriteLine("Outer: " + q.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}

Console.WriteLine("Done");
Console.ReadLine();
}


/// <summary>
/// Call the dumy dll with a reference to the DataContainer.
/// </summary>
[DllImport("foo.dll", EntryPoint = "LeakClass", CallingConvention =
CallingConvention.Cdecl)]
public static extern int LeakClass(ref DataContainer cl);

}
}

foo.h:
typedef struct _DataContainer {
int m_arrayBindIndex;
} DataContainer;

extern "C" {
// Declaration of the compression method
__declspec(dllexport) void LeakClass(DataContainer **flum);
};

foo.cpp:
// This is the main DLL file.
#include <objbase.h>
#include "foo.h"

void LeakClass(DataContainer ** flum) {
}


(Don't comment on the usefullness of the code, it is only an example, as is
probably obvious from the naming etc. :))

Running the program and attaching DebugDiag will reveal that on every call
to the unmanaged method there is a leak of 4 bytes. The leak will be on the
default process heap due to a call to CoTaskMemAlloc (used by the
interop-marshaler). DebugDiag reports that the allocations come from
mscorwks!BlittablePtrMarshalerBase::ConvertSpaceCLRToNative+23 . I can even
remove the only field in the class DataContainer passed to the unmanaged
method, this will result in a leak of 1 byte per call. The leak is not in
managed memory, but just to avoid all replys about "The GC hasn't run yet.."
etc. I included the GC.Collect()-sequence.
The above problem arises in our production servers. These small memory leaks
will fragment the default process heap (CoTaskMemAlloc heap) eventualy
crashing the app.
So, am I doing something stupid here? I have read about pinvoke and interop
marshaling but I can't find anything that is wrong with the code. Changing
the managed definition to a struct solves the problem. I would still like to
know what is wrong with the code I posted above.
Hope someone has some insight into thi.
/Erik
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top