关于C#中内存管理,托管内存和非托管内存的问题(比较棘手)
时间:2011-12-28
来源:互联网
一.我在C#中要调用VC编写的DLL,核心算法都是在VC中写的,里面也涉及到大量的内存的分配和释放。但是在调用DLL里的函数时,有时可以调用通过,有时不能调用通过,我在VC中定位的,出问题的地方都是在分配内存后,进行内存拷贝的地方,如:
C/C++ code
我之前一直怕C#这边有内存泄露,导致这样的问题存在,所以我优化过很多次,对于非托管资源Pen,Font,Brush,Graphics,Bitmap(主要是Bitmap图像的释放),在不需要的时候都进行了释放。
就算VC中的DLL函数可以调用通过,如果连续运行几次,在C#这边申请一个比较大的数组比如 double类型,大小为2048*1536*9就会报出“内存不足”的错误,但是物理内存是肯定够用的,我定义了一些工具类用于存放调用DLL计算后得到的一些数据,用数组存储,但是对于数组,在C#中不能手工对其进行释放,我在《C#高级编程》中,看到它用实现IDispose接口和析构函数来加速托管资源和非托管资源的释放,代码如下:
C# code
这样在代码中调用对象的Dispose方法,就释放托管内存和非托管内存,传递Dispose(bool disposing)的参数表示是用析构函数调用还是IDispose的Dispose()调用,真正实现清理的是该函数,这样做可以保证所有清理代码都放在一个地方。GC.SuppressFinalize();告诉垃圾回收器这个类不再需要调用其析构函数了,因为Dispose()已经完成了所有需要的清理工作,所以析构函数不需要做任何工作了。我的问题就是Dispose(bool disposing)中释放托管资源的地方的代码,对于我的类中含有的数组这些资源,我还是没办法手工进行释放的啊?所以这些数组资源的释放该如何释放呢?
二.对于软件中需要的一些模态窗口,因为使用ShowDialog方法显示的窗口的关闭,并没有对其进行释放,所以我在Form_Closing方法中加了Dispose方法,但是我用AQTime测过,这些模态窗口并没有释放掉,是不是和我将窗口作为参数传给下一个窗口有关?
三.在定义类的字段成员变量后,我喜欢随即初始化,但是这样会存在有时候没用到该变量时,也对其进行了初始化,造成了少量内存的浪费,比如一个引用类型的数组,这在AQTime中也会反映出来,如果在其初次使用的时候对其初始化,我觉得不怎么方便容易出错,还不怎么正规。
反正在这个项目上内存的问题弄得我很头疼,我能用的方法都用出来了,有些问题还是没办法解决。
C/C++ code
double *Image = new double[width*height]; for(i=0; i<width*height; i++) *(Image+i) = *(Src_Image+i);
我之前一直怕C#这边有内存泄露,导致这样的问题存在,所以我优化过很多次,对于非托管资源Pen,Font,Brush,Graphics,Bitmap(主要是Bitmap图像的释放),在不需要的时候都进行了释放。
就算VC中的DLL函数可以调用通过,如果连续运行几次,在C#这边申请一个比较大的数组比如 double类型,大小为2048*1536*9就会报出“内存不足”的错误,但是物理内存是肯定够用的,我定义了一些工具类用于存放调用DLL计算后得到的一些数据,用数组存储,但是对于数组,在C#中不能手工对其进行释放,我在《C#高级编程》中,看到它用实现IDispose接口和析构函数来加速托管资源和非托管资源的释放,代码如下:
C# code
public class Graphics2DShow:IDisposable { public virtual void Dispose() { Dispose(true); GC.SuppressFinalize(); } protected virtual void Dispose(bool disposing) { if(!isDisposed) { if(disposing) { //释放图片非托管资源 } //释放托管资源 } isDisposed = true; } ~Graphics2DShow() { Dispose(false); } }
这样在代码中调用对象的Dispose方法,就释放托管内存和非托管内存,传递Dispose(bool disposing)的参数表示是用析构函数调用还是IDispose的Dispose()调用,真正实现清理的是该函数,这样做可以保证所有清理代码都放在一个地方。GC.SuppressFinalize();告诉垃圾回收器这个类不再需要调用其析构函数了,因为Dispose()已经完成了所有需要的清理工作,所以析构函数不需要做任何工作了。我的问题就是Dispose(bool disposing)中释放托管资源的地方的代码,对于我的类中含有的数组这些资源,我还是没办法手工进行释放的啊?所以这些数组资源的释放该如何释放呢?
二.对于软件中需要的一些模态窗口,因为使用ShowDialog方法显示的窗口的关闭,并没有对其进行释放,所以我在Form_Closing方法中加了Dispose方法,但是我用AQTime测过,这些模态窗口并没有释放掉,是不是和我将窗口作为参数传给下一个窗口有关?
三.在定义类的字段成员变量后,我喜欢随即初始化,但是这样会存在有时候没用到该变量时,也对其进行了初始化,造成了少量内存的浪费,比如一个引用类型的数组,这在AQTime中也会反映出来,如果在其初次使用的时候对其初始化,我觉得不怎么方便容易出错,还不怎么正规。
反正在这个项目上内存的问题弄得我很头疼,我能用的方法都用出来了,有些问题还是没办法解决。
作者: mjjackey 发布时间: 2011-12-28
非托管代码三种内存分配、释放方式:
malloc free
new delete
CoTaskMemAlloc CoTaskMemFree
内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存,可以不用显示释放内存,net帮你搞定!而其他两种,net不支持的方式,必须还是由非托管方来释放!也就是:你要做C++和C#两边都封装一个相应的释放函数!
malloc free
new delete
CoTaskMemAlloc CoTaskMemFree
内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存,可以不用显示释放内存,net帮你搞定!而其他两种,net不支持的方式,必须还是由非托管方来释放!也就是:你要做C++和C#两边都封装一个相应的释放函数!
作者: sdl2005lyx 发布时间: 2011-12-28
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28