Memory leak in NETCF SP3 on WM2003SE using PInvoke

D

David Brunning

Not sure, but I believe that the compact framework SP3 leaks memory
when using PInvoke on Windows Mobile 2003 Second Edition.

I have two applications - the first is a framework application that
updates a SQLCE database using DataSets and DataAdapters. The
database is synchronised with a central database using CE Merge
Replication and I initially thought that I had to populate the rowguid
column myself on the device so there is a PInvoke call to
CryptAcquireContext in order to build a Guid (There is an article on
MSDN on how to here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/html/PPCGuidGen.asp).

The second application was written when the first seemed to be leaking
memory and is a memory profiler which PInvokes to GlobalMemoryStatus
to log memory usage on the device over time (Another article on MSDN
here http://msdn.microsoft.com/smartclient/community/cffaq/cf10.aspx#cfw0ezz1
under "Device Capabilities and Capacity").

Running app 1 results in an out of memory exception in the PocketGuid
class and logging memory usage with the profiler clearly shows memory
load increasing at an alarming rate (Goes up 40% in about 10 minutes)

I wondered if the profiler was the problem so ran that with nothing
else on the device to baseline memory usage over 10 minutes and adjust
the memory profile of app 1 accordingly - it was clearly not although
the profiler app did seem to contribute to the problem.

So, I removed the guid generation from app 1 and reprofiled - memory
usage now doesn't appear to go up anywhere near as much - the only
leak now is from the profiling application which makes a PInvoke call
itself.

The profiling application source code is available for download here:
http://exc01.ccsit.co.uk/davidbrunning/Memory/MobileProfiler.zip

To reiterate - this problem appears to be limited to Windows Mobile
2003 Second Edition (4.21.1088) - with an older IPAQ running Pocket PC
2003 (4.20.1081) the problem doesn't seem to occur - or at least
occurs less obviously.

Could someone try this on a WM2003SE device (Mine is an hp iPAQ hx2110
which uses an Intel PXA270) and tell me if I'm wrong?

This is something which is on the release note for .NET CF SP3 as
being fixed - but I'm not sure it has.

Thanks
 
P

Peter Foot [MVP]

If you are solely targetting devices based on CE 4.2 and above (e.g. Pocket
PC 2003 and 2003 Second Edition) the easiest way to create a guid is using
the CoCreateGuid API call:-
http://blog.opennetcf.org/pfoot/PermaLink.aspx?guid=296990fd-10ee-4c56-a9d6-d60d7716c1f6

Not only does this use less resouces (and less code) but it's also quicker
to execute since all the hard work is done in native code in the COM
subsystem. This is not supported on older versions of CE so you have to
resort to the Cryptography route.

Looking at the code in the article there isn't anything to suggest a memory
leak, and the GC should collect when it sees a low memory condition
approaching. Could it be that you are allocating native memory anywhere else
in the application and not releasing it?

Peter
 
D

David Brunning

I don't really believe it is a memory leak any more - I've been trying
all afternoon to reproduce the problem and am having very limited
success.

When I left my profiler running for longer the memory usage got to
about 80% and stopped rising. I will continue in my efforts to repro
- if anyone has any ideas feel free to pass them on!

Thanks for listening... :)
 
D

David Brunning

Hi Peter,
Thanks for the response. I have removed the need for GUIDs on the
device now (I am relying on replication to sort of the rowguid column
rather than populating it myself - something which I am sure I wasn't
able to do pre SP3...?)

Running the profiler for longer it does appear that it simply takes a
long time for the garbage collector to get up and running properly -
if I leave the profiler running for more than 10 minutes then usage
hits about 80% and hovers there - going up in steps which look like
page allocations (Normal behaviour I guess).

I'm confused now though because I am having problems repro'ing the
problem.

Have you got any good advice on handling exceptions raised by native
code?

Thanks
 
D

David Brunning

The saga continues. Here is the code from the PocketGuid class that
is failing:

// imports for the crypto api functions
private class WinApi
{
public const uint PROV_RSA_FULL = 1;
public const uint CRYPT_VERIFYCONTEXT = 0xf0000000;

[DllImport("coredll.dll")]
public static extern bool CryptAcquireContext(
ref IntPtr phProv, string pszContainer, string pszProvider,
uint dwProvType, uint dwFlags);

[DllImport("coredll.dll")]
public static extern bool CryptReleaseContext(
IntPtr hProv, uint dwFlags);

[DllImport("coredll.dll")]
public static extern bool CryptGenRandom(
IntPtr hProv, int dwLen, byte[] pbBuffer);

[DllImport("coredll.dll")]
public static extern double GetLastError();
}

...
...

if (!WinApi.CryptAcquireContext(ref hCryptProv, null, null,
WinApi.PROV_RSA_FULL, WinApi.CRYPT_VERIFYCONTEXT))
{
string ReturnValue="";
try {ReturnValue=WinApi.GetLastError().ToString();}
catch (System.Exception exc)
{ ReturnValue="not specified.("+exc.Message+")"; }
throw new KeystoneCryptographyException("Failed to acquire
cryptography handle. (Return value is "+ReturnValue+")");
}


It is pretty much verbatim the sample from MSDN. The failure is this
- the WinApi.CryptAcquireContext returns false which drops into the if
block - in the try block the WinApi.GetLastError call raises a
NotSupportedException. I've tried to pull back and read a stack trace
for this exception but I get a MissingMethodException when I do.

I can run the example above a certain number of times before it falls
over. The time it falls over memory load is over 80% on the device
(Device has 128Mb of memory). The device is an HP hx2110 running
Windows Mobile 2003 Second Edition with the Compact Framework SP 3
deployed. Without SP3 the exception never gets raised (i.e. if I
deploy the project immediately after a hard reset). Another
interesting fact (?) is that if I run in debug mode the exception
never gets raised - it only happens with a build release deployed to
the device and without the debugger connected.

I really am stuck - I've worked around the problem by removing the
need for the above PInvokes but am having nagging doubts in the back
of my mind so any further ideas on how to get to the root of it would
be greatly appreciated.

Thanks
 

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