interop >> Interop Memory Leak....

by Cliff » Sat, 03 Jun 2006 03:39:40 GMT

I'm using someone else's code to lookup a TCP Table...

I'm having trouble withe the app as after about 24 hours usage its at
500MB memory...

Their code uses interop to call a Win32 Function or too....and uses
AllocHGlobal and FreeHGlobal.

When Running the code having put Debug statements around the allocs and
free's I can see that they are matching....something like this...

AllocMemory 2031488
DE - AllocMemory 2031488
AllocMemory 2031488
DE - AllocMemory 2031488
AllocMemory 1956632
DE - AllocMemory 1956632
AllocMemory 1956632
DE - AllocMemory 1956632
AllocMemory 1956632
DE - AllocMemory 1956632
AllocMemory 1956632
DE - AllocMemory 1956632

I more or less know its the Win32 side of things causing the problem
becuase I've used the .net memory profiler by Scitech....and that shows
the "Win32Heap" increasing. All other objects are more or less static
(as I'd expect them to be)

What this tends to suggest to me is that the FreeHGlobal Calls aren't
working.

Is that possible?

What else can I do to try and find this leak?

Any help appreciated.

I would put the code here but it would be too long. If anyone fancies a
shot, I'll email you the code...get me on
Cli#ffd#abbs@h#o#t#m#a####i##l.com without the #s obveiously.

Thanks

Cliff.


interop >> Interop Memory Leak....

by lgs.lgs » Sat, 03 Jun 2006 06:28:17 GMT


> Their code uses interop to call a Win32 Function or too....and uses

It's possible that you aren't actually leaking. Perhaps what you have is
just fragmentation. I just had this problem with some other software I was
writing.

Consider:

1) You request a 10k chunk via AllocHGlobal
2) The os allocates the memory.
3) You use the memory
4) You release the memory

Now, some other chunk of code needs 56 bytes off that same heap. The os
looks and says "here's a 10k chunk that's not being used, I'll give you the
first 56 bytes out of that."

When you get back around to asking for your next 10k chunk, it finds that it
can't use the old one (there's 56 bytes too few), so it asks the os for
*another* 10k chunk.

For educational purposes, can you AllocHGlobal the memory once and hang on
to it? Re-using the same pointer over and over again would prove (or
eliminate) this as the source
of the problem.


What Win32 functions does this other code call? Perhaps handle or something
is being returned that in that memory block that also needs to be released.

interop >> Interop Memory Leak....

by Scott M. » Sat, 03 Jun 2006 08:42:59 GMT

Are you using:

System.Runtime.InteropServices.Marshall.ReleaseCOMObject(COMObjectReference)

to ensure that the CLR releases it's reference to the COM object before the
.NET object variable loses scope?

interop >> Interop Memory Leak....

by Cliff » Sat, 03 Jun 2006 19:29:36 GMT


interop >> Interop Memory Leak....

by Scott M. » Sat, 03 Jun 2006 22:33:54 GMT

Rather than having others go and download your code, maybe you could just
post the code here? And, how about answering my question about using
ReleaseComObject?

interop >> Interop Memory Leak....

by Cliff » Sun, 04 Jun 2006 06:38:05 GMT

ppologies....in answer to your question...I don't think so...but I
don't believe I'm using Com objects either.

I got to that conclusion in a bit of a round about way, looking
throught the code, I can't see anything anything using Com Objects and
I can't see anything I would pass into
ReleaseCOMObject(COMObjectReference so I can't see how it would be
of help.

ok, I'll try to list the relavant code here...but there's really too
much of it I'm not 100% sure whats relavant...remember this is not my
code...

The DLLImports are:
[DllImport("iphlpapi.dll",
EntryPoint="AllocateAndGetTcpExTableFromStack")]
private static extern DWORD GetTcpTableEx(IntPtr ppTcpTableEx,
[MarshalAs(UnmanagedType.Bool)]
bool bOrder,
IntPtr hProcHeap,
[MarshalAs(UnmanagedType.U4)]
DWORD dwReserved, // Reserved. Set to 0
[MarshalAs(UnmanagedType.U4)]
DWORD dwFlags); // Must be 2

[DllImport("iphlpapi.dll", EntryPoint="GetTcpTable")]
private static extern DWORD GetTcpTable(IntPtr pTcpTable,
IntPtr pdwSize,
[MarshalAs(UnmanagedType.Bool)]
bool bOrder);

#endregion

There are some other classes involved but this is the main one...

#region public class TcpTable : IDisposable
public class TcpTable : IDisposable
{
#region Nested Classes

#region public class TcpRow
public class TcpRow
{
#region Win32 Constants
// _MIB_TCPROW dwState constants
private const int MIB_TCP_STATE_CLOSED = 1;
private const int MIB_TCP_STATE_LISTEN = 2;
private const int MIB_TCP_STATE_SYN_SENT = 3;
private const int MIB_TCP_STATE_SYN_RCVD = 4;
private const int MIB_TCP_STATE_ESTAB = 5;
private const int MIB_TCP_STATE_FIN_WAIT1 = 6;
private const int MIB_TCP_STATE_FIN_WAIT2 = 7;
private const int MIB_TCP_STATE_CLOSE_WAIT = 8;
private const int MIB_TCP_STATE_CLOSING = 9;
private const int MIB_TCP_STATE_LAST_ACK = 10;
private const int MIB_TCP_STATE_TIME_WAIT = 11;
private const int MIB_TCP_STATE_DELETE_TCB = 12;

#endregion


#region Fields
private int _iState = 0;
private IPAddress _ipaddrLocal = IPAddress.None;
private int _iLocalPort = 0;
private string _strLocalPortKeyword = string.Empty;
private string _strLocalPortDescription = string.Empty;
private IPAddress _ipaddrRemote = IPAddress.None;
private int _iRemotePort = 0;
private string _strRemotePortKeyword = string.Empty;
private string _strRemotePortDescription = string.Empty;
private int _iProcessId = -1;

#endregion


#region Properties
public int State
{
get { return _iState; }
set { _iState = value; }
}

public string StateDescription
{
get
{
string strTemp = string.Empty;
switch(_iState)
{
case MIB_TCP_STATE_CLOSED:
strTemp = "CLOSED";
break;
case MIB_TCP_STATE_LISTEN:
strTemp = "LISTENING";
break;
case MIB_TCP_STATE_SYN_SENT:
strTemp = "SYN_SENT";
break;
case MIB_TCP_STATE_SYN_RCVD:
strTemp = "SYN_RECEIVED";
break;
case MIB_TCP_STATE_ESTAB:
strTemp = "ESTABLISHED";
break;
case MIB_TCP_STATE_FIN_WAIT1:
strTemp = "FIN_WAIT1";
break;
case MIB_TCP_STATE_FIN_WAIT2:
strTemp = "FIN_WAIT2";
break;
case MIB_TCP_STATE_CLOSE_WAIT:

interop >> Interop Memory Leak....

by Scott M. » Sun, 04 Jun 2006 21:16:12 GMT

he definition of InterOp is .NET applications using COM objects or COM
applications using .NET objects. Your situation is the former.

Win32 functions are held in COM libraries. The .dll's you are referencing
that do not belong to the .NET Framework are COM libraries. Any objects you
instantiate from those libraries must explicitly be destroyed by the .NET
Common Language Runtime (CLR) with the Marshall.ReleaseCOMObject(obj) code.

I am not familiar enough with C# or this particluar API you are calling to
pinpoint your coding error. But you are, in fact, using COM quite
extensively in your code (anywhere you see "unmanaged type" in one
indication).


"Cliff" < XXXX@XXXXX.COM > wrote in message
news: XXXX@XXXXX.COM ...
Appologies....in answer to your question...I don't think so...but I
don't believe I'm using Com objects either.

I got to that conclusion in a bit of a round about way, looking
throught the code, I can't see anything anything using Com Objects and
I can't see anything I would pass into
ReleaseCOMObject(COMObjectReference so I can't see how it would be
of help.

ok, I'll try to list the relavant code here...but there's really too
much of it I'm not 100% sure whats relavant...remember this is not my
code...

The DLLImports are:
[DllImport("iphlpapi.dll",
EntryPoint="AllocateAndGetTcpExTableFromStack")]
private static extern DWORD GetTcpTableEx(IntPtr ppTcpTableEx,
[MarshalAs(UnmanagedType.Bool)]
bool bOrder,
IntPtr hProcHeap,
[MarshalAs(UnmanagedType.U4)]
DWORD dwReserved, // Reserved. Set to 0
[MarshalAs(UnmanagedType.U4)]
DWORD dwFlags); // Must be 2

[DllImport("iphlpapi.dll", EntryPoint="GetTcpTable")]
private static extern DWORD GetTcpTable(IntPtr pTcpTable,
IntPtr pdwSize,
[MarshalAs(UnmanagedType.Bool)]
bool bOrder);

#endregion

There are some other classes involved but this is the main one...

#region public class TcpTable : IDisposable
public class TcpTable : IDisposable
{
#region Nested Classes

#region public class TcpRow
public class TcpRow
{
#region Win32 Constants
// _MIB_TCPROW dwState constants
private const int MIB_TCP_STATE_CLOSED = 1;
private const int MIB_TCP_STATE_LISTEN = 2;
private const int MIB_TCP_STATE_SYN_SENT = 3;
private const int MIB_TCP_STATE_SYN_RCVD = 4;
private const int MIB_TCP_STATE_ESTAB = 5;
private const int MIB_TCP_STATE_FIN_WAIT1 = 6;
private const int MIB_TCP_STATE_FIN_WAIT2 = 7;
private const int MIB_TCP_STATE_CLOSE_WAIT = 8;
private const int MIB_TCP_STATE_CLOSING = 9;
private const int MIB_TCP_STATE_LAST_ACK = 10;
private const int MIB_TCP_STATE_TIME_WAIT = 11;
private const int MIB_TCP_STATE_DELETE_TCB = 12;

#endregion


#region Fields
private int _iState = 0;
private IPAddress _ipaddrLocal = IPAddress.None;
private int _iLocalPort = 0;
private string _strLocalPortKeyword = string.Empty;
private string _strLocalPortDescription = string.Empty;
private IPAddress _ipaddrRemote = IPAddress.None;
private int _iRemotePort = 0;
private string _strRemotePortKeyword = string.Empty;
private string _strRemotePortDescription = string.Empty;
private int _iProcessId = -1;

#endregion


#region Properties
public int State
{
get { return _iState; }
set { _iState = value; }
}

public string StateDescription
{
get
{
string strTemp = string.Empty;
switch(_iState)
{
case MIB_TCP_STATE_CLOSED:
strTemp = "CLOSED";
break;
case MIB_TCP_STATE_LISTEN:
strTemp = "LISTENING";
bre

interop >> Interop Memory Leak....

by Scott M. » Tue, 06 Jun 2006 06:35:15 GMT

> Interop is NOT defined as interoperating with COM objects. Interop is

You are splitting hairs here Stephen. COM objects ARE unmanaged code, thus
calling them means using COM InterOp.


Again, splitting hairs. Win32 functions are held in unmanged .dll's (a COM
library).

I didn't notice the PInvoke, so you may be correct about calling
ReleaseCOMObject(obj), but my definitions are correct.

interop >> Interop Memory Leak....

by Willy Denoyette [MVP] » Tue, 06 Jun 2006 15:41:35 GMT


|> Interop is NOT defined as interoperating with COM objects. Interop is
| > simply interoperating with unmanaged code - through COM Interop, C style
| > function exports, internal calls across the managed/unmanged barrier in
| > C++/CLI, etc.
|
| You are splitting hairs here Stephen. COM objects ARE unmanaged code,
thus
| calling them means using COM InterOp.
|
Not necessarely, 'COM objects' can also be implemented in managed code, even
using a scripting language (think vbscript, jscript etc..), granted all code
that run's on windows is finally unmanaged code, but we are talking about
implementation right?

| > Win32 functions are not held in COM libraries but are, in general, C
style
| > exports from unmanaged DLLs.
|

Win32 functions are in general not exported from COM libraries (though you
can), they are exported from generic DLL's, static lib's or object files,
ready for consumption by Win32 clients adhering to the Windows function
binding protocol (import/export). COM 'functions' require COM object
binding, that means you need the COM library to actually instantiate objects
and call their methods.
| Again, splitting hairs. Win32 functions are held in unmanged .dll's (a
COM
| library).
|
No really, unmanaged dll's don't have to be "COM libraries". COM libraries,
are DLL's that do implement special export function, these exports are
required by the COM library (Ole32.dll) and are not required to be present
in generic libraries.

Willy.

interop >> Interop Memory Leak....

by Cliff » Tue, 06 Jun 2006 18:54:14 GMT

Sometimes I love Microsoft.....

I started this project in .net 1 and I'm now in .net 2...

turns out .net 2 contains a proper managed implementation of
GetTCPTable which is what I'm after...so I've replaced all that code up
there with

IPGlobalProperties properties =
IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] connections =
properties.GetActiveTcpConnections();

foreach (TcpConnectionInformation t in connections)
{
if ((t.LocalEndPoint.Port = 21) |
t.RemoteEndPoint.Port = 21)
return true;
}
return false;

Job done...

Thanks anyway guys...!

Cliff.

Similar Threads

1. COM Interop Memory Leak

We're converting over an ASP site to ASP.NET and have written .NET
class libraries that are used from ASP.NET and from ASP via COM
Interop. When we deploy our changes to our production server everything
seems to run fine for about a day with page file usage in Task Manager
at around 200-300MB and the w3wp.exe process using about 180MB
(physical memory is 1GB). CPU usage hovers between 15 - 25%.

Then after one day of running fine the memory usage seems to shoot up.
The page file goes up to 2GB and the w3wp.exe process churns through
all available memory. CPU usage shoots up to 100%.

We've tried enabling application recycling and setting a memory cap of
600MB. Sometimes this helps and another day or two will pass before
another recycle takes place. Other times recycling occurs repeatedly
with only minutes between recycles because W3wp.exe consumes all the
memory moments after it's restarted.

Our server is running W2k3 Web Edition.

The problem appears to be caused COM Interop. Our class doesn't do much
- it basically opens an SQL connection does a few DB things and closes
the connection. 

Any help would be greatly appreciated.

2. Flash OCX Memory Leak, Or .Net Framework Memory Leak

3. Memory leak using interop for OS Authentication

4. Memory leak in interop

5. Debug output tells memory leak (using .NET app with C++ interop dl

I am not sure this is the right forum. Could be Visual Studio C/C++ or VS #C. 
But here is the description:

We are working on a .NET program which uses several dlls, both pure c# DLL'S 
and dll's written in C++ interop and in addition 3 party SW from several 
vendors.
The managed C++ dll are wrappers for interfacing native C++ code which we 
have link in as static libraries.
When we exit the program we get very many indications on memroy leaks dumped 
by the function _CrtDumpMemoryLeaks. After debugging a bit, the problem is 
that at the time _CrtDumpMemoryLeaks is called (destructor of afxState class 
inside MFC 8.0 dll), several of the managed C++ dll's are not unloaded, thus 
their static/global C++ objects destructors have not been called. 
Since we use system multithreaded dll's they share the same heap. 
Is there a way to be sure that _CrtDumpMemoryLeaks are called after all 
destructors have been called for all dll's? On stop the _CrtDumpMemoryLeaks 
called from the destructor of afxState?



6. COM Interop and memory leaks

7. memory leak with com interop

Hi,

I am trying to find out where there is a memory leak in our
application.  I have created a test harness in C# to test this.

I'm basically hitting the object (written in c++) really hard by
looping through it

Here is the code in c#:
###################################
for (int i = 0; i<= 10000000; i++)
{
BPTACACSLib.TacacsAuthenicateClass tac = new
BPTACACSLib.TacacsAuthenicateClass();
string sessKey = tac.GetSessionKey("test", "dev", "127.0.0.1");

}
##################################
The instantiation of this object is eating up memory like crazy not the
GetSessionKey method.  I know this because I've seen no change in
memory when I move the instanitation call outside the loop.

I have no clue as to why its eating the memory.

Here is the method if anyone wants to look in c++:

#########################################
STDMETHODIMP CTacacsAuthenicate::GetSessionKey(BSTR user, BSTR
password, BSTR IPaddress, BSTR *sessionKey)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState())
	_bstr_t bstrUser(user);
	_bstr_t bstrPassword(password);
	_bstr_t bstrIPaddress(IPaddress);

	char sSession[40]; memset( sSession, '\0', 40 );

	CTacacsPlus tacacs;
	tacacs.TacacsAuthenticate((LPCTSTR) bstrUser, (LPCTSTR) bstrPassword,
(LPCTSTR) bstrIPaddress, sSession);
	_bstr_t bstrSessionKey(sSession);
	*sessionKey = bstrSessionKey.copy();

	return S_OK;
}

##########################################

Now if I call the COM object in ASP page it is NOT eating up memory
like I've described above.

This COM object is registered as a COM+ application in the component
services as well.

1. Can anyone help/direct me to know why the memory is being eaten up
on the instantiation or is there something I can do.  What else can I
do to narrow down the problem and solve it.

2. Is there a reason why the memory doesn't get eaten up on regular asp
while it does on C# test harness?

8. Interop events leak memory (again)