C# 在picturebox控件中显示位图后处理它
我想知道为什么垃圾收集器不能跟踪位图的非托管部分使用的内存量,并在需要时释放此资源 我是在后台线程中的一个循环调用以下函数时发现的,该函数在一段时间后导致异常:C# 在picturebox控件中显示位图后处理它,c#,winforms,bitmap,garbage-collection,picturebox,C#,Winforms,Bitmap,Garbage Collection,Picturebox,我想知道为什么垃圾收集器不能跟踪位图的非托管部分使用的内存量,并在需要时释放此资源 我是在后台线程中的一个循环调用以下函数时发现的,该函数在一段时间后导致异常: private delegate void setImageCallback(); private void showFrame() { if (pboxCam.InvokeRequired) { this.Invoke(new setImageCallba
private delegate void setImageCallback();
private void showFrame()
{
if (pboxCam.InvokeRequired)
{
this.Invoke(new setImageCallback(showFrame));
}
else
{
Bitmap bmp = new Bitmap(getBitmapFromCam());
Graphics g = Graphics.FromImage(bmp);
g.DrawRectangle(RectanglePen, 10, 10, 50, 30);
g.Dispose();
pboxCam.Image = bmp;
}
}
然后我尝试在函数的末尾释放bmp,但是picturebox不再显示图像。
下面的解决方案确实有效,但有一点我不喜欢。你觉得怎么样
Bitmap bmp;
private delegate void setImageCallback();
private void showFrame()
{
if (pboxCam.InvokeRequired)
{
this.Invoke(new setImageCallback(showFrame));
}
else
{
if (bmp!=null) bmp.Dispose();
bmp = new Bitmap(getBitmapFromCam());
Graphics g = Graphics.FromImage(bmp);
g.DrawRectangle(RectanglePen, 10, 10, 50, 30);
g.Dispose();
pboxCam.Image = bmp;
}
}
你做得对。GC正在跟踪
位图
对象,并最终将其释放。关键词是“最终”
要回收托管的bmp
实例,它首先必须遇到内存压力。这发生在gen-0集合的大约1个MiB处。我不确定确切的数字,但关键是数量很多。在进入gen-0集合之前,您将拥有数千个位图(如果不是更多的话),并且您通常需要gen-2来执行终结器(尽管对此有点怀疑,我不知道在哪里找到了这些信息)
即使GC最终运行(实际上,在此之前很长一段时间内存就会用完),它也会开始在单独的线程上执行终结器。它不知道非托管资源,因此它必须依赖于它串行运行的终结器代码。它根本不知道分配了多少非托管内存,也无法在内存检查中计算出来
因此,关键是始终在IDisposable
对象上运行Dispose
。GC甚至可能没有机会在内存耗尽之前启动终结器,因为它只是由托管内存压力引起的。它不知道非托管内存(如果有)。这不是地面军事系统的错,它真的不知道-毕竟,在你的确切情况下,内存是共享的。GC甚至不知道是否应该释放内存-这取决于位图。最终确定来决定
这也是为什么您确实希望使所有使用任何IDisposable
或非托管内存(也就是IDisposable
)的内容都可用的原因,以确保调用者能够尽快释放本机资源
这不仅仅适用于非托管内存-等待GC处理文件句柄或套接字连接是一个坏主意,因为您确实不希望保存这些文件的时间超过需要的时间。导致异常没有帮助。什么例外?设置消息、异常名称和堆栈跟踪是否在循环中设置了PictureBox
。我认为这显然是一个OutOfMemoryException。@Hamlet Hakobyan,函数本身是在一个循环中调用的,该循环从摄像机中检索帧。我同意你的看法,但op说它抛出了OutOfMemoryException
对此表示怀疑:(@SriramSakthivel我扩展了我的答案,希望回答你的怀疑:)@Sriram Sakthivel,我有一张屏幕的打印图,但最好不要在这里显示。请相信我:)它出现的那一行是Bitmap bmp=new Bitmap(getBitmapFromCam());我的问题是,为什么它没有实现一种机制来给GC增加等于为像素数据分配的内存量(可以很容易地计算)的压力?@GiuseppeDini.NET不知道这一点。GDI+处理这个问题,这是一个本机的非托管库。即使是这样,也不是托管内存压力,所以它和GC无关。它甚至不必分配任何内容,或者完全不同的应用程序可能会使用相同的位图数据。非托管就是这样-非托管。你没有真正的记忆追踪。我很高兴GC没有猜到:)本机句柄包装在托管句柄中这一事实使您免于泄漏(很好),而不是内存不足(您的错误)。