8

When I call an unmanaged C++ code from my C# code, I seem to have some kind of a memory leak.
The C++ reads data from a file using ifstream.read, and writes it to a Vector.

This happens only after upgrading to Windows 7, doesn't happen on Vista, but if I use a version of the native dll that was compiled on Vista, it doesn't change anything!
If I run the same C++ code directly, without the managed interope, there is no memory leak!
If I run the managed process, but within the vshost process, there is no memory leak!

Here's the call signature:

        [DllImport(DllPath, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.I1)]
    public static extern bool MyMethod(
        int x, 
        string  y, 
        string  z, 
        bool    v, 
        bool    w);

and the native one:

MyDll_Export bool APIENTRY MyMethod(
int x,
const wchar_t*  y, 
const wchar_t*  z,
bool v,
bool w)

When I call it from C++, I call it like this:

MyMethod(1, L"My String 1", L"My String 2", true, true)

When I look at the performance counters for managed and unmanaged memory, I see that all of the memory comes from the unmanaged code.
Considering that the marshaling is pretty simple, I don't understand why there is a difference between calling the C++ directly or through C#.
I also don't know why would this happen only on Windows 7 (both Windows installations had .net 3.5 SP1).

Does anyone have an idea what's the reason for this?

Also if anyone knows of a native memory profiling tool that works on Window 7, I'd be glad to know (for now I've just printed to console all explicit memory allocation and there are no differences).

Meidan Alon
  • 3,074
  • 7
  • 45
  • 63
  • LeakDiag [http://mcfunley.com/277/using-leakdiag-to-debug-unmanaged-memory-leaks] or AutomatedQA's AQTime can do unmanaged leak analysis. – Lou Franco Oct 01 '09 at 18:31
  • Which performance counter do you use for measuring memory consumption? – Peter Mortensen Oct 03 '09 at 13:55
  • You have tagged the question "vshost.exe". Does the application run under Visual Studio when you measure memory consumption? – Peter Mortensen Oct 03 '09 at 13:58
  • @Lou: neither works on Windows 7. @Peter: I checked "Process - private bytes" for native allocations, and CLR memory for managed. I tagged vshost.exe because "If I run the managed process, but within the vshost process, there is no memory leak", the memory measures were down on the regular process. – Meidan Alon Oct 03 '09 at 16:50

4 Answers4

5

I'm sure the problem is related to marshaling the C# data types to their C++ counter parts. Since you are marshaling the return value bool to a signed 1 byte value, maybe you should do the same to the function arguments? The C# bool type is 4 bytes, maybe you are leaking there?

Also, specifying the unmanaged type for the strings may help.

[DllImport(DllPath, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool MyMethod(
        int x,
        [MarshalAs(UnmanagedType.LPWStr)]
        [In] string y,
        [MarshalAs(UnmanagedType.LPWStr)]
        [In] string z,
        [MarshalAs(UnmanagedType.I1)]
        bool v,
        [MarshalAs(UnmanagedType.I1)]
        bool w);

An explanation for the commentor:

For the C++ bool type:

In general, a zero or null-pointer value is converted to false, any other value is converted to true.

...

The 1998 C++ Standard Library defines a specialization of the vector template for bool. The description of the class indicates that the implementation should pack the elements so that every bool only uses one bit of memory.

So, pretty much whatever value you use, you'll get a c++ boolean with the value true or false.

scottm
  • 27,829
  • 22
  • 107
  • 159
  • If the bool's mismatched on size it wouldn't be a memory leak, but more probably an access violation, or some sort of stack corruption. – user7116 Oct 05 '09 at 15:02
  • nice file scott, c# marshals bools as 4bytes. The marshalas attribute was missing for v and w. http://blogs.msdn.com/oldnewthing/archive/2009/08/13/9867383.aspx – Hasani Blackwell Oct 05 '09 at 15:06
  • thanks, that's a nice read but it didn't help. as I mentioned in another comment, I call this method only once, so even if there was a leak there, it wouldn't be noticeable. – Meidan Alon Oct 05 '09 at 15:52
  • @Meidan Alon, how much memory are you leaking when you call the method? – scottm Oct 05 '09 at 16:01
  • I've measure at 2 points in time. Without the leak private bytes are at 37k and 66k; with the leak it's at 90k and 1.7G. So it's growing really fast! – Meidan Alon Oct 05 '09 at 16:18
  • At this point, I think you are going to have to add more information about the managed code. I'm guessing the reason your unmanaged code doesn't leak is because the leak is not in this function. – scottm Oct 05 '09 at 16:41
2

Unfortunately once you involve strings, no marshalling is simple.

We're going to need some more data in order to help you track down this problem. Can you provide the following

  • Native Method Signature
  • How is the memory for the strings managed in native code?
  • Perhaps the C++ sample where you use the API?

EDIT

Try the following signature. This tells the CLR not to marshal memory in both directions but instead only pass the data in.

    [DllImport(DllPath, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.I1)]
    public static extern bool MyMethod(
            int x, 
            [In] string  y, 
            [In] string  z, 
            bool    v, 
            bool    w);
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • the [In] didn't help, why would it change between Vista and Windows 7? also, I didn't mention that I call this method only once. – Meidan Alon Oct 02 '09 at 10:23
1

I found the use of the CLR Profiler helpful when finding my memory leak.

mike
  • 3,146
  • 5
  • 32
  • 46
0

Are you sure that there is a memory leak?

What is your basis for determining the memory leak. You say that you can see it from performance counters, but what do you actually observe? Do you see a coninously rising curve, or one that settles on a high level? A high memory consumption is often confused for a memory leak.

btw. Can you post you C++ function definition as well?

Pete
  • 12,206
  • 8
  • 54
  • 70
  • I see a continuously rising curve. i've posted the C++ function definition, if you mean the body, then it just reads data from a file using ifstream.read – Meidan Alon Oct 05 '09 at 10:12