【问题标题】:Out of memory exception in WPF applicationWPF 应用程序中的内存不足异常
【发布时间】:2013-09-15 18:05:04
【问题描述】:

我正在创建一个应用程序,我从相机获取实时图像并尝试将其放在 WPF 的图像控制上。但是一段时间后它会开始抛出内存不足的异常。

代码如下:

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
}

这是堆栈跟踪:

   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)

有没有办法可以减少内存消耗并找到解决此内存不足异常的方法?

【问题讨论】:

  • 您可以使用缓冲区并以块的形式读取/保存文件
  • 可以发一下OOM的stacktrace吗?
  • 您发布的代码中似乎没有“泄漏”内存。问题可能来自其他地方。堆栈跟踪会很有帮助。
  • 图像可能太大,在堆中。

标签: c# .net wpf memory-management out-of-memory


【解决方案1】:

我建议您遭受大对象堆 (LOH) 碎片的困扰。有什么办法可以将图像大小减小到 85K 字节以下,这样它们就不会碰到 LOH?

【讨论】:

  • 如果 .NET 版本是最新的,LOH 应该不是问题。
  • Err... 直到 4.5.1,这是一个巨大的问题。 blogs.msdn.com/b/mariohewardt/archive/2013/06/26/…
  • 除非您为微软不支持的 Windows XP 编写代码,否则我认为没有理由不使用最新版本的 .NET。此外,IIRC,对 LOH 问题有几个逐步修复,.NET 4.5.1 中的手动 GC.Collect 并不是真正修复它的功能,而是顶部的樱桃。
  • @AllanElder 我使用的是 4.0 完整版。
  • 如果您在企业环境中工作,有很多原因不能编码到最新最好的。假设您在诸如 LOH 碎片这样众所周知的主题上对内存使用没有任何问题,这只是粗心编码的借口。
【解决方案2】:

如果您使用的是 .NET 4.5.1,则可以使用 on-demand LOH compaction

【讨论】:

    【解决方案3】:

    我确实面临同样的情况,现在我不得不用另一个人来完成这个,我会分享这个。

    在这里,我发布了在列表视图项中添加图像以获取缩略图视图。同样,通过改变图片的宽高,你可以通过bitmapsource对象的返回值得到你想要的。

    步骤 1

    导入DLL文件文件:

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

    第二步

    /// <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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多