views:

609

answers:

4

Hi all,

I've got what I assume is a memory fragmentation issue.

We've recently ported our WinForms application to a WPF application. There's some image processing that this application does, and this processing always worked in the WinForms version of the app. We go to WPF, and the processing dies. Debugging into the library has the death at random spots, but always with an array that's nulled, ie, allocation failed.

The processing itself is done in a C++ library called by a p/invoke and is fairly memory intense; if the given image is N x M pixels big, then the image is N x M x 2 bytes big (each pixel is an unsigned short, and it's a greyscale image). During the processing, image pyramids are made, which are in float space, so the total memory usage will be N x M x (2 + 2 + 4 + 4 + 4 + 4), where the first 2 is the input, the second 2 is the output, the first 4 is the input in floats, the second 4 is the 0th level difference image, and the last two fours are the rest of the pyramid (since they're pyramids and each level is half the size in each direction, these 4s are upper bounds). So, for a 5000x6000 image, that's 600 mb, which should fit into memory just fine.

(There's the possibility that using marshalling is increasing the memory requirement by another N x M x 4, ie, the input and output images on the C# side and then the same arrays copied to the C++ side-- could the marshalling requirement be bigger?)

How fragmented is WPF compared to WinForms? Is there a way to consolidate memory before running this processing? I suspect that fragmentation is the issue due to the random nature of the breakages, when they happen, and that it's always a memory allocation problem.

Or should I avoid this problem entirely by making the processing run as a separate process, with data transfer via sockets or some such similar thing?

+2  A: 

If I read this correctly, the memory allocation failure is happening on the non-managed side, not the managed side. It seems strange then to blame WPF. I recognize that you are drawing your conclusion based on the fact that "it worked in WinForms", but there are likely more changes than just that. You can use a tool like the .NET Memory Profiler to see the differences between how the WPF application and the WinForms application are treating memory. You might find that your application is doing something you don't expect. :)

Per comment: Yup, I understand. If you're confident that you've ruled out things like environment changes, I think you have to grab a copy of BoundsChecker and Memory Profiler (or DevPartner Studio) and dig in and see what's messing up your memory allocation.

JP Alioto
I've gone over that processing code many times. If it's leaking or misbehaving, I'm just not seeing it; but the breaks definitely started happening when we went to WPF from winforms. The code is otherwise identical.
mmr
+1  A: 

I'm guessing that the GC is moving your memory. Try pinning the memory in unmanaged land as long as you have a raw pointer to the array, and unpin it as soon as possible. It's possible that WPF causes the GC to run more often, which would explain why it happens more often with it, and if it's the GC, then that would explain why it happens at random places in your code.

Edit: Out of curiosity, could you also pre-allocate all of your memory up front (I don't see the code, so don't know if this is possible), and make sure all of your pointers are non-null, so you can verify that it's actually happening in the memory allocation, rather than some other problem?

FryGuy
pinning? The dll is declaring all of its scratch memory inside itself. If the GC is wandering all over the place, then that really would mean going into another process, just to avoid such wonky behavior.
mmr
Well, are the pointers to *gcnew* objects, or *new* objects? I was assuming that you were taking an int* to the raw pixel data out of a Bitmap class. The GC could pick up the bitmap and move it while you are running.
FryGuy
yeah, I'm not doing that. I'm using DICOM images, which are not bitmaps. The visualization is done as openGL textures, and the images themselves are just arrays-- in the C# app, they're ushorts, and in the C++ dll, they become floats, in order to have negative values and enough dynamic range.So, they are to 'new' objects.
mmr
A: 

It sounds like you want to be more careful about your memory management in general; ie: either run the processing engine in a separate address space which carefully manages memory, or pre-allocate a sufficiently large chunk before memory gets too fragmented and manage images in that area only. If you're sharing address space with the .NET runtime in a long-running process, and you need large contiguous areas, it's always going to potentially fail at some point. Just my 2c.

Nick
So, basically, just go to a second process is what I'm hearing. Why would it always potentially fail? What's .NET doing here that makes it so unstable?
mmr