[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework.interop

Marshal.PtrToStringAnsi() Memory Leak?

(Saby)

7/12/2007 9:39:00 PM

I've been noticing a memory leak with the following sample code
snippet. Can someone please advise.

Have a C# Winforms app with the following code on a button-click
event.

private void button1_Click(object sender, System.EventArgs e)
{
IntPtr p1 = new IntPtr(-1);
string inputStr;
AllocString(out p1); //AllocString() called via Interop
string managedStr = Marshal.PtrToStringAnsi(p1);
Thread.Sleep(20);
Marshal.FreeHGlobal(p1);

}

The method AllocString() is defined in a C-DLL as:
CDLL_API void AllocString(char** inputStr)
{
int len = 10000000;
char * x = (char *) GlobalAlloc(0, len+1);
memset(x,65,len);
x[l]=0;
*inputStr = x;
}

On launching the application, the steady state private bytes is 10MB.

On clicking the button, I see private bytes increase by 30MB. Why the
additional overhead of 20MB for PtrToStringAnsi()? And this 20MB is
never freed. Also confirmed that the bytes allocated are in the
unmanaged code, since the .NET "# Bytes in All Heaps" never increases.

If I comment the Marshal.PtrToStringAnsi() line, private bytes always
comes back to 10MB.

Is this expected behavior for Marshal.PtrToStringAnsi() ? (.NET
Framework 1.1)

3 Answers

Michael Phillips, Jr.

7/12/2007 11:55:00 PM

0

> Is this expected behavior for Marshal.PtrToStringAnsi() ? (.NET
> Framework 1.1)

It looks like the expected behavior.

Per the MSDN documentation, PtrToStringAnsi allocates a managed ANSI string
and widens it to UNICODE when it copies your unmanaged string.

Your code allocates an unmanaged string of 10,000,000 bytes which is copied
to a managed string of 20,000,000 bytes.

A managed string's memory exists until it is garbage collected.


<sabys@hotmail.com> wrote in message
news:1184276338.850234.219780@o61g2000hsh.googlegroups.com...
> I've been noticing a memory leak with the following sample code
> snippet. Can someone please advise.
>
> Have a C# Winforms app with the following code on a button-click
> event.
>
> private void button1_Click(object sender, System.EventArgs e)
> {
> IntPtr p1 = new IntPtr(-1);
> string inputStr;
> AllocString(out p1); //AllocString() called via Interop
> string managedStr = Marshal.PtrToStringAnsi(p1);
> Thread.Sleep(20);
> Marshal.FreeHGlobal(p1);
>
> }
>
> The method AllocString() is defined in a C-DLL as:
> CDLL_API void AllocString(char** inputStr)
> {
> int len = 10000000;
> char * x = (char *) GlobalAlloc(0, len+1);
> memset(x,65,len);
> x[l]=0;
> *inputStr = x;
> }
>
> On launching the application, the steady state private bytes is 10MB.
>
> On clicking the button, I see private bytes increase by 30MB. Why the
> additional overhead of 20MB for PtrToStringAnsi()? And this 20MB is
> never freed. Also confirmed that the bytes allocated are in the
> unmanaged code, since the .NET "# Bytes in All Heaps" never increases.
>
> If I comment the Marshal.PtrToStringAnsi() line, private bytes always
> comes back to 10MB.
>
> Is this expected behavior for Marshal.PtrToStringAnsi() ? (.NET
> Framework 1.1)
>


(Saby)

7/13/2007 12:33:00 AM

0


> It looks like the expected behavior.
>
> Per the MSDN documentation, PtrToStringAnsi allocates a managed ANSI string
> and widens it to UNICODE when it copies your unmanaged string.
>
> Your code allocates an unmanaged string of 10,000,000 bytes which is copied
> to a managed string of 20,000,000 bytes.
>
> A managed string's memory exists until it is garbage collected.

Interesting. If its copying over to a "managed" string of 20MB, I
would expect the Perfmon .NET "# Bytes in All Heaps" counter to
increase by 20MB. (Since its allocating on the managed heap). But,
this counter does not change.
Instead, the "Private Bytes" counter is increasing by 20MB.

Also, tried GC.Collect but doesn't seem to drop the Private Bytes..
which seem to imply the memory is allocated on the unmanaged heap?





Willy Denoyette [MVP]

7/13/2007 12:52:00 PM

0

<sabys@hotmail.com> wrote in message
news:1184276338.850234.219780@o61g2000hsh.googlegroups.com...
> I've been noticing a memory leak with the following sample code
> snippet. Can someone please advise.
>
> Have a C# Winforms app with the following code on a button-click
> event.
>
> private void button1_Click(object sender, System.EventArgs e)
> {
> IntPtr p1 = new IntPtr(-1);
> string inputStr;
> AllocString(out p1); //AllocString() called via Interop
> string managedStr = Marshal.PtrToStringAnsi(p1);
> Thread.Sleep(20);
> Marshal.FreeHGlobal(p1);
>
> }
>
> The method AllocString() is defined in a C-DLL as:
> CDLL_API void AllocString(char** inputStr)
> {
> int len = 10000000;
> char * x = (char *) GlobalAlloc(0, len+1);
> memset(x,65,len);
> x[l]=0;
> *inputStr = x;
> }
>
> On launching the application, the steady state private bytes is 10MB.
>
> On clicking the button, I see private bytes increase by 30MB. Why the
> additional overhead of 20MB for PtrToStringAnsi()? And this 20MB is
> never freed. Also confirmed that the bytes allocated are in the
> unmanaged code, since the .NET "# Bytes in All Heaps" never increases.
>
> If I comment the Marshal.PtrToStringAnsi() line, private bytes always
> comes back to 10MB.
>
> Is this expected behavior for Marshal.PtrToStringAnsi() ? (.NET
> Framework 1.1)
>


The memory allocated by GlobalAlloc (or LocalAlloc) is not returned to the
OS after freeing, it is kept in the process space for successive use. This
memory will be reclaimed by the OS when there is memory pressure.
Note also, that your code has a *bug* in the sense that you are allocating
using "GlobalAlloc" and de-allocating using "LocalFree" (implicitely called
by FreeHGlobal). LocalFree must be paired with LocalAlloc.