我发现,在使用
GC.Collect();
GC.WaitForPendingFinalizers();
后,在任务管理器中看到内存回收胜少!原来40多M,回收后还是40多M!
但当我最小化窗口后内存一般会减少到2M左右。
再还原窗口后,内存占用也只有8M多。问题就来啦!.Net是不是在我们最小化窗口时作了什么手脚?把内存回收了?我们自己调用GC.Collect()为什么回收不了那部分内存而最小化可以做到?

解决方案 »

  1.   

    .net自动管理内存的,不能确定他什么时候开始管理,也许是一秒钟也许是一小时,是随机的
      

  2.   

    最大最小化窗体跟.net的垃圾回收机制没有关系吧。你随便打开一个资源管理器之类的程序也能看到内存占用的大小变化。http://www.yesky.com/20030311/1656401.shtml
      

  3.   

    理论上Collect() 允许对象释放可能用到的资源,但是在实践中这种方法是不可靠的,
    实际上Collect() 仅对大多数程序员罕见的少数的特殊情况有用,而大多数情况是没有用的
    不要依赖于Collect() 方法
      

  4.   

    使用垃圾回收器最好的方法就是跟踪程序中定义的对象,在程序不需要它们的时候手动释放它们。例如程序中的一个对象中有一个字符串属性,该属性会占用一定的内存空间。当该属性不再被使用时,开发人员可以在程序中将其设定为null,这样垃圾回收器就可以回收该字符串占用的空间。另外,如果开发人员确定不再使用某个对象时,需要同时确定没有其它对象引用该对象,否则垃圾回收器不会回收该对象。
      

  5.   

    问题就来啦!.Net是不是在我们最小化窗口时作了什么手脚?把内存回收了?我们自己调用GC.Collect()为什么回收不了那部分内存而最小化可以做到?最小化窗体的时候内存没有回收,只是因为任务管理器中对于程序占用内存数的计算方法和其他程序不同而已。
      

  6.   

    可能你最小化窗口之前,还有一些GDI资源(例如HDCD)之类的资源没有释放,所以GC.Collect是没有效果的。
      

  7.   

    1、任务管理器显示的是物理内存占用量,不包括页面文件上交换过去的内存
    2、任务管理器显示的物理内存占用量,也不完全都是程序自己占用的,有些内核对象占用的空间也被计算在内
    3、GC.Collect 方法并不保证回收所有无法访问的内存可以这么写(这个技巧来自《.NET 框架程序设计》):
    // 先强制回收一次内存(内存仍未释放,因为对象还要"复苏",然后执行Finalize方法)
    GC.Collect();
    // 等待所有对象的Finalize方法调用完成
    GC.WaitForPendingFinalizers();
    // 再次回收(此时内存空间才会被真正释放)
    GC.Collect();窗口最小化时内存占用量下降,是因为Windows自动把程序此进程不常用的内存交换到页面文件,把内存空间让给活动窗口
    这个特性对于所有Windows程序默认都一样(除非通过SetProcessWorkingSetSize API直接指定working set大小),当然也包括.NET程序
      

  8.   

    最小化后GDI资源被释放了并且暂时也不会在申请GDI资源了 是这样吗
      

  9.   

    在窗体重会的时候要获取gdi资源绘画然后释放
    窗口最小化后窗体没有重会事件产生所以占用的内存变小了
    我记得以前在别的地方看到过类似的帖子
    这样的理解不对吗 为什么
      

  10.   

    同意Sunmast(速马|一切皆有可能)的说法,补充一点,Collect()这个东西不是万能钥匙,很多情况下还是自己在程序中把对象=null再Collect()才可能把不用的资源释放。
      

  11.   

    @fireyan
    对象 = null或者离开作用范围均可
    反过来说如果不是的话Collect()也没用,那个是前提@mm521
    绘制窗口的过程速度极快且不会占用多少内存,这个不会是重点
    另外如果你说的GDI资源是Device Context的话,这是系统内核对象,它占用的内促是不会因为最小化窗口而释放的
    在前面已经说过,内存占用变小是假象,任务管理器只报告了物理内存占用,程序占用的内存只是从一个地方移到另一个地方而已
      

  12.   

    malloc(),程序员编写的代码通常尽可能少地调用 malloc(),因为他们知道分配的开销相当大。这种方式转换为以块进行分配的做法,通常是猜测性地分配我们可能需要的对象,以便我们可以进行总数更少的分配。然后从某种分配池对预先分配的对象进行手动管理,从而有效地创建一种高速度的自定义分配器。在托管世界中,由于下面几个原因内存的使用不同,首先,执行分配的开销非常小 — 因为不需要像传统分配器那样搜索可用的内存块;所有需要发生的操作只是需要移动在可用的和已分配的区域之间的边界。分配的开销很小意味着使用池来管理内存分配的最有吸引力的理由不再存在。其次,如果您确实要选择预分配方式,当然会使所产生的分配量比立即需要方式所需的分配量更多,这反过来会强制执行额外的垃圾回收操作,而这在其他方式下可能是不需要的。 最后,垃圾回收器将无法回收手动回收的对象的空间,因为从全局角度来看,所有这些对象(包括当前没有使用的对象)仍然是活的。可能会发现,随时待用的方式会让很多内存被浪费,但正在使用中的对象则不会。这并不是说预分配方式总是糟糕的想法。例如,您可能希望通过这样做强制将某些对象一开始就分配在一起,但您可能发现,与在非托管代码中相比,将它作为一种常规策略不那么有吸引力。我估计是使用了。NET托管的原因~~~~(以上说法全是引用别人的,最后一句才是自己写的,呵呵)
      

  13.   

    GC Heap上分配内存的速度确实非常的快,直接在Heap末端分配,并且假设总是有可用的空间
    但是这个速度源于GC在GC Heap上不断移动对象位置使之挨个相连,性能在这里消耗了
      

  14.   

    一定要强制释放资源吗?对于一些占用资源不多的对象让.net自己处理应该会更好一点的
      

  15.   

    Sunmast正解。在托管应用程序中,缩小变量的作用域即可减轻内存开销,当然,最重要的还是少用那些巨耗内存的东西。例如一万个元素的ArrayList,一万条记录的DataSet等。在C#中,任意一对花括号中都可以成为一个作用域,善于使用这个特性还能使我们的程序清晰易懂:
    最常见的作用域:for ( int i = 0 ; i < a.length; i++ )//i的作用域仅限于for花括号内。using ( IDbConnection Connection = GetConnection() )
    {
      DataSet ds = new DataSet();//仅限于using块内
      .....
    }
    GC.Collect();//可以释放上面的DataSet当然,我们也可以人为的创造一些作用域,避免变量名称冲突和减轻内存开销。{
      int i;
      ......
    }{
      int i;
      .....
    }如果为了编排好看可以这样:
    if ( true )//执行某任务
    {
      int i;
      ......
    }
      

  16.   

    if ( true )//执行某任务
    {
      int i;
      ......
    }
    这种语句块没用的,值类型都在堆栈之上
    DataSet的那个理论上要好那么一点点,加入它真的很大的话
      

  17.   

    试试这一句: GC.Collect(2); 除非有绝对把握,最好不要参与 GC 的操作。
      

  18.   

    http://community.csdn.net/Expert/topic/3777/3777394.xml?temp=.8133661
      

  19.   

    微软的例子Duwamish7中DataAccess里的books继承IDisposable,你是不是也... 问:为什么DataAccess里的books要从IDisposable继承?
    答:IDisposable接口:定义一种释放分配的非托管资源的方法。
    作为数据访问层,很重要的一个方面是数据库连接等资源释放的问题。虽然.NET技术提供了有关当托管对象不再使用时,垃圾回收器会自动释放分配给该对象的内存的机制。但是,进行垃圾回收的时间不可预知。另外,垃圾回收器对打开的文件,数据库连接等非托管资源一无所知。由此就可能产生问题,有一些数据库连接资源,连接对象等未得到及时的释放,这样将引起资源浪费,系统性能下降等问题。将IDisposable接口的Dispose方法与垃圾回收器一起使用来显示释放非托管资源。当不再需要对象时,对象的使用者可以调用此方法。这种方法可以有效地释放资源,提高系统性能。
      

  20.   

    可以这么写(这个技巧来自《.NET 框架程序设计》):
    // 先强制回收一次内存(内存仍未释放,因为对象还要"复苏",然后执行Finalize方法)
    GC.Collect();
    // 等待所有对象的Finalize方法调用完成
    GC.WaitForPendingFinalizers();
    // 再次回收(此时内存空间才会被真正释放)
    GC.Collect();
    这个方法没有试过。不知道是不是奏效。等有时间测试一下。那位有时间就写个测试,把结果贴出来大家参考。
      

  21.   

    参考一下这里:http://www.cnblogs.com/wljcan/archive/2004/12/24/81540.html
      

  22.   

    这个问题在 .net框架设计修订版 里有转门的一章来讲,看完就可以理解透彻了
      

  23.   

    我看到过net写的程序很大的,却内存比想像的要小的多,速度也比想像的要快
    不明白