开发环境
VS2022
SimpleITKCSharplanaged.dll 4.11
现象
调用某给出的方法时出现下述错误:
引发的异常:“System.ApplicationException”(位于SimpleITKCSharpManaged.dll 中)“System.pplicationException”类型的常在 SimpleITKCSharplanaged.dll中发生,但未在用户代码中进行处理Exception thrown in SimplelTk Resamplenagerilter Execute: c:dvs10-04-pkglsinpleitk-buildlitk- prefixincludelitk-4. 1litknportInagecontainer.hxx:19 Failed to allocate memory for image.
详细如下截图:
分析
从看到的“Failed to allocate memory for image.” 这条信息来看,就是分配给image的内存失败了。于是怀疑程序对于某些需要释放的对象没有正常的释放(可能是托管对象,也可能是非托管对象),导致其在资源不能被回收,同时每次调用还在实例化,导致其内存占用就不断增长。
以下为出错时的内存快照,可以看出内存确实是在不断增长的,增长到接近71.2G的样子。在内存耗尽之后,肯定就会出现不能分配内存的问题。
下图为程序报错时的情况,报错后程序的内存也明显得到了释放。但是再次运行时又会内存激增。
解决方案
查看某给出的调用方法中的Image,如下图所示,其都是由itk中提供的Image。
itk中的Image应该是有一个Dispose方法,尝试可知itk中的Image确实是有Dispose方法的,也就是说Image是需要显示释放资源的,否则就会造成它的资源不能被及时回收,从而导致其内存激增,最后导致整个程序运行报错。
在将image及时Dispose后,再次运行程序,这次内存没有再出现内存激增的情况。
C#常见需要Dispose对象
对于C#这种托管语言,大多数时候是不需要显示释放资源的,但一些非托管的资源必须手动进行释放。
常见的如:
文件流——文件读取时常用
内存流
图像——图像处理的时候常用,主要是Bitmap
进程——进程操作或多进程处理
更多的可详细见IDisposable的派生类。
如何预防
特别注意,对于调用他人开发的dll或程序时,一定要仔细查看资源是否需要显示Dispose,若需要释放,则一定要释放。
除了开发时注意外,还有就是提到的诊断工具要利用起来。在提交代码前,最好在监控内存的情况下运行下程序,最大限度的避免此类错误提交到了仓库中。监控时,主要观察内存是否激增,对象数量是否有明显增加。
最后就是不断总结、积累。毕竟成长的路上,谁又不会摔倒呢?