我使用第三方库,它是本机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.AddMemoryPressure
或GC.RemoveMemoryPressure
只是让垃圾收集更频繁地运行,我现在的问题是我有小对象可以处理大型非托管内存,而GC不是收集这些小物件。
----编辑----
调用GC.Collect
将在运行时解决问题,我设置了一个定时器并定期调用GC.Collect
,但它会使应用程序冻结一段时间,所以我不想使用这种方法。
答案 0 :(得分:0)
我发现GC
有局限性,在非常沉重的压力和记忆密集的应用下可能效果不佳。我有一个应用程序,它不直接对非托管资源,所有标准.NET组件做任何事情,它仍然可以阻塞内存。它可以使用GB的RAM但不是因为巨大的内存需求,而是因为大对象的创建和销毁相对较快而且显然不会经常收集。应用程序没有内存泄漏,因为在强制收集时它们都被释放。看起来GC
并不总是能够按时收集未使用的对象,即OutOfMemoryException
之前。它等待找到最好的时刻,但在它决定之前,为时已晚。当我定期强制收集时,应用程序运行没有问题。
值得一提的是,OutOfMemoryException
并不总是意味着你实际上没有自由记忆。它也可能意味着没有足够大的连续内存块可用。特别是在处理视频和图像时可能会出现这种情况。 GC
可能认为仍有大量内存可用,但它对于您的应用程序而言过于分散。我确信GC
会将碎片考虑在内,但有可能它并不总是正确的。
如果您确定图书馆不是问题,我的建议是尝试更多内存压力方法(AddMemoryPressure和RemoveMemoryPressure)以帮助GC
按时完成。它可以解决您的问题,因为您使用的是非托管库,可能会处理GC
后面的大量内存。或者像处理GC.Collect
一样。手动收集可能并不理想,但我相信有些情况是合理的。当然,预计手动收集大量对象可能会对您的应用程序性能产生影响。
修改强>
如果手动收集会对性能产生太大影响,请尝试使用GC.Collect
的重载版本来提供更多控制。