+ -
当前位置:首页 → 问答吧 → 关于C#中内存管理,托管内存和非托管内存的问题(比较棘手)

关于C#中内存管理,托管内存和非托管内存的问题(比较棘手)

时间:2011-12-28

来源:互联网

一.我在C#中要调用VC编写的DLL,核心算法都是在VC中写的,里面也涉及到大量的内存的分配和释放。但是在调用DLL里的函数时,有时可以调用通过,有时不能调用通过,我在VC中定位的,出问题的地方都是在分配内存后,进行内存拷贝的地方,如:
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#两边都封装一个相应的释放函数!

作者: sdl2005lyx   发布时间: 2011-12-28