-1

I am creating an application where I am getting live images from camera and trying to put that on image control of WPF. But after some time it will start throwing out of memory exception.

Here is the code:

try
{
    imgControl.Dispatcher.Invoke(DispatcherPriority.Normal,
    (Action)(() =>
    {
        using (MemoryStream memory = new MemoryStream())
        {
            lastImage.Save(memory, ImageFormat.Png);
            memory.Position = 0;
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = memory;
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.EndInit();

            ImageSource imageSource = bitmapImage;
            imgControl.Source = imageSource;
        }
    }));
}
catch (Exception ex)
{
    //Exception handling
}

Here is stack trace:

   at System.Windows.Media.Composition.DUCE.Channel.SyncFlush()
   at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable`1 channelSet)
   at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam)
   at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)

Is there a way I can reduce memory consumption and find a work around for this out-of-memory exception?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sunder
  • 1,803
  • 4
  • 29
  • 50
  • You could use a buffer and read / save your files in chunks – clamchoda Sep 11 '13 at 15:53
  • Can you post the OOM's stacktrace please? – Christian.K Sep 11 '13 at 15:54
  • Nothing seems "leaking" memory in the code you posted. Probably the problem is from somewhere else. A stack-trace would be of great help. – Mohammad Dehghan Sep 11 '13 at 15:57
  • The image probably is too large that is in the heap. – 123 456 789 0 Sep 11 '13 at 15:58
  • How you manage `lastImage`? – Hamlet Hakobyan Sep 11 '13 at 15:59
  • guys I keep on getting this lastImage(Bitmap object) from live camera, so I am keep on updating image. So its like live video from camera. – sunder Sep 11 '13 at 16:10
  • 5
    See this blog post: [“Memory leak” with BitmapImage and MemoryStream](http://code.logos.com/blog/2008/04/memory_leak_with_bitmapimage_and_memorystream.html). – Bradley Grainger Sep 11 '13 at 16:16
  • I have added stacktrace as well for error – sunder Sep 11 '13 at 16:20
  • Can you put some info about your Image for example camera image size, Your camera make images 16 bits or 8 bits? Your Image Format some cameras have own Image formats. – Bassam Alugili Sep 11 '13 at 18:09
  • Doubt is will fix it but try moving the new BitmapImage() out of the loop and also not new the MemoryStream() as suggested by Athari. – paparazzo Sep 11 '13 at 19:21
  • How are you displaying the images in the WPF control? It could be that the WPF presentation layer is creating too many controls and keeping them in memory - using a VirtualizingStackPanel as the container on the UI could help reduce memory overhead. – benPearce Sep 11 '13 at 22:33
  • @BradleyGrainger: I had the same problem some time ago: http://stackoverflow.com/questions/6271891/net-memory-issues-loading-40-images-memory-not-reclaimed-potentially-due-to. There is a fix in there as well. – Ed S. Sep 14 '13 at 05:19
  • I'm getting this problem in .NET 4.6.1. Does this solution still apply? – SuperJMN Jul 21 '16 at 07:28

3 Answers3

0

I would suggest you're suffering from Large Object Heap (LOH) fragmentation. Is there any way you can reduce the image size below 85K bytes so that they will not hit the LOH?

Allan Elder
  • 4,052
  • 17
  • 19
  • If .NET version is recent, LOH should not be an issue. – Athari Sep 11 '13 at 16:04
  • Err... up until 4.5.1, it is a HUGE issue. http://blogs.msdn.com/b/mariohewardt/archive/2013/06/26/no-more-memory-fragmentation-on-the-large-object-heap.aspx – Allan Elder Sep 11 '13 at 16:22
  • Unless you code for Windows XP, which is unsupported by MS, I see no reason not to use the most recent version of .NET. Also, IIRC, there were several gradual fixes to the LOH problem, and manual `GC.Collect` from .NET 4.5.1 is not the feature that actually fixed it, but a cherry on the top. – Athari Sep 11 '13 at 16:27
  • @AllanElder I am using 4.0 full version. – sunder Sep 11 '13 at 16:29
  • 1
    If you work in an enterprise environment, there are many reasons for not coding to the latest and greatest. Assuming you'll have no issues with memory usage on such a well known topic as LOH fragmentation is just an excuse for inattentive coding. – Allan Elder Sep 11 '13 at 18:49
  • What makes you think the image is on the GC heap in the first place? – Gabe Sep 11 '13 at 21:10
  • The Image itself, once loaded, is a Win32 object. The objects being used to load the Image into memory are on the heap; if the image is more than 85K bytes, it would stand to reason they'll be hitting the LOH. Repeatedly creating these objects would cause the LOH to grow and grow, even though they are being collected by GC, there is no compaction taking place on that heap. Just a theory.. without running through the profiler, it's difficult to say for sure. – Allan Elder Sep 11 '13 at 22:29
  • @AllanElder Now that I think of it, LOH shouldn't be an issue with this code even in older .NET versions. `MemoryStream` allocates blocks of sizes 2^N. Under normal conditions, these blocks will be reused. Therefore, compaction is unnecessary. – Athari Sep 12 '13 at 01:41
0

If you are on .NET 4.5.1 you can do on-demand LOH compaction.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rohit Sharma
  • 6,136
  • 3
  • 28
  • 47
0

I do face the same situation, and now I had to finish this with an alternate one, and I will share that.

Here I have posted for adding images in a listview item for a thumbnail view. Similarly, by changing the width and height of an image you can get what you wanted through the return value of a bitmapsource object.

Step 1

Import the DLL file file:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

Step 2

/// <summary>
/// Gets the thumnail of the source image.
/// </summary>
/// <returns></returns>

private BitmapSource GetThumbnail(string fileName)
{
    BitmapSource returnis = null;
    using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fileName))
    {
        IntPtr hBitmap = GenerateThumbnail(bmp, 50);
        try
        {
           returnis = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                        hBitmap,
                        IntPtr.Zero,
                        Int32Rect.Empty,
                        System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                }
                finally
                {
                    DeleteObject(hBitmap);
                }
            }
            return returnis;
        }

/// <summary>
/// GenerateThumbnail image.
/// </summary>
/// <param name="original">Image</param>
/// <param name="percentage">int</param>
/// <returns>Image</returns>

public static IntPtr GenerateThumbnail(System.Drawing.Image original, int percentage)
{
    try
    {
        if (percentage < 1)
        {
            throw new Exception("Thumbnail size must be at least 1% of the original size.");
        }
        Bitmap tn = new Bitmap((int)(original.Width * 0.01f * percentage), (int)(original.Height * 0.01f * percentage));
        Graphics g = Graphics.FromImage(tn);
        g.InterpolationMode = InterpolationMode.HighQualityBilinear;

        //Experiment with this...
        g.DrawImage(original,
                    new System.Drawing.Rectangle(0, 0, tn.Width, tn.Height),
                    0,
                    0,
                    original.Width,
                    original.Height,
                    GraphicsUnit.Pixel);
        g.Dispose();
        return tn.GetHbitmap();
    }
    catch (Exception ex)
    {
        return IntPtr.Zero;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sabnew
  • 1
  • 2