使用非托管资源

时间:2012-05-13 07:19:43

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

我使用第三方库,它是本机dll的包装器。该库包含XImage类型,XImage具有一些属性和IntPtr Data()方法。 XImage也实现IDisposable,但我不知道它是否正确实施。

我从TCP连接中获得了许多XImage并在PictureBox中将它们显示为电影。

我曾经将'XImage'转换为System.Drawing.Image并在PictureBox中查看,但我得到了AccessViolationException

所以我围绕XImage制作了一个名为Frame的包装器。

public class Frame : IDisposable
{
  public uint size { get; private set; }
  private Image image;
  public XImage XImage { get; set; }
  public Image Image { get { return image ?? (image = GetBitmap(this.XImage)); } }
  public DateTime Time { get; set; }

   public Frame(XImage xImage)
  {
    this.XImage = xImage;
    this.size = XImage.ImageBufferSize();
    GC.AddMemoryPressure(size);
  }


  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }

  ~Frame()
  {
    Dispose(false);
  }

  protected virtual void Dispose(bool disposing)
  {
    if (disposing)
    {
      try
      {
        image.Dispose();
      }
      catch { }
      finally
      {
        image = null;
      }
      try
      {
        MImage.Dispose();
      }
      catch { }
      finally { XImage = null; }
    }
    GC.RemoveMemoryPressure(size);
  }
}

并且通过处理对Frame的引用,我解决了AccessViolationException。 现在我有另一个问题,当我从visual studio运行程序时(F5 - 开始调试)一切正常,但是当我从.exe文件或(ctrl + F5 - Start without debugging)运行时,内存使用情况越来越大,直到我得到OutOfMemoryException。(Biuld配置:发布 - X86)。我该怎么办?

----编辑----

我发现GC.AddMemoryPressureGC.RemoveMemoryPressure只是让垃圾收集更频繁地运行,我现在的问题是我有小对象可以处理大型非托管内存,而GC不是收集这些小物件。

----编辑----
调用GC.Collect将在运行时解决问题,我设置了一个定时器并定期调用GC.Collect,但它会使应用程序冻结一段时间,所以我不想使用这种方法。

1 个答案:

答案 0 :(得分:0)

我发现GC有局限性,在非常沉重的压力和记忆密集的应用下可能效果不佳。我有一个应用程序,它不直接对非托管资源,所有标准.NET组件做任何事情,它仍然可以阻塞内存。它可以使用GB的RAM但不是因为巨大的内存需求,而是因为大对象的创建和销毁相对较快而且显然不会经常收集。应用程序没有内存泄漏,因为在强制收集时它们都被释放。看起来GC并不总是能够按时收集未使用的对象,即OutOfMemoryException之前。它等待找到最好的时刻,但在它决定之前,为时已晚。当我定期强制收集时,应用程序运行没有问题。

值得一提的是,OutOfMemoryException并不总是意味着你实际上没有自由记忆。它也可能意味着没有足够大的连续内存块可用。特别是在处理视频和图像时可能会出现这种情况。 GC可能认为仍有大量内存可用,但它对于您的应用程序而言过于分散。我确信GC会将碎片考虑在内,但有可能它并不总是正确的。

如果您确定图书馆不是问题,我的建议是尝试更多内存压力方法(AddMemoryPressureRemoveMemoryPressure)以帮助GC按时完成。它可以解决您的问题,因为您使用的是非托管库,可能会处理GC后面的大量内存。或者像处理GC.Collect一样。手动收集可能并不理想,但我相信有些情况是合理的。当然,预计手动收集大量对象可能会对您的应用程序性能产生影响。

修改

如果手动收集会对性能产生太大影响,请尝试使用GC.Collect的重载版本来提供更多控制。