none
怎么才能强制回收datatable对象占用的内存? RRS feed

  • 问题

  • 我打开一个窗体,之后 填充了14W条数据到datatable对象里面,这个datatable对象是窗体级的变量,我在form_closing的时候调用了了下面的代码,可占用的那部分内存还是没有回收到:

          if (dtbl!=null)
    
          {
    
            dtbl.BeginLoadData();
    
            dtbl.Clear();
    
            dtbl.EndLoadData();
    
            dtbl.Dispose();
    
            GC.SuppressFinalize(dtbl);
    
            GC.Collect(0);
            GC.Collect(1);
            GC.Collect(2);
    
          }
    我用进程管理器看了一下占用的内存大概有200多M,可当我关闭创建的窗体时,哪儿跟内存占用还是没有释放出来,,因为读取一次,占用的内存确实太多了,所以想在窗体关闭的时候,释放占用的这部分内存

     

    2010年5月17日 16:55

答案

  • 你好!

          首先,不建议你把如此多的数据都加载到DataTable中,只加载需要的数据就可以了!

          其次,不建议你调用GC.Collect方法来强制执行垃圾回收,执行一次垃圾回收本身的性能开销就很大,包括遍历所有的根,构造可达对象图,为终止化可达链表中的对象执行终止化,“压内存”!CLR本身是有一定的算法来判断在何时执行这个操作性价比最好!你手动调用的时机很可能不合适!

          最后,垃圾回收操作是在单独的线程中执行的,所以即使你使用GC.Collect方法来强制垃圾收集,也不一定马上就看到效果,因为他要执行上面提到的那些工作,而且是在其他线程中进行,和操作系统的线程调度有一定关系的!


    周雪峰
    2010年5月18日 1:34
    版主
  • 你好  我新建了个测试窗体 是可以释放的 最开始打开窗体内存占用大道200多MB关闭后就只有40多MB了 如果最小化以下主窗体 那么则只有几MB了(所以可以让窗体最小化  再显示就可以快速减少内存)

    如果不添加回收那段代码 即便窗体关闭 内存也不会马上下降的,由此可见GC是发挥了作用的。

     public partial class DataTableForm : Form
        {
            public DataTableForm()
            {
                InitializeComponent();
                InitializeDataTable();
                this.FormClosing += new FormClosingEventHandler(DataTableForm_FormClosing);
            }

            void DataTableForm_FormClosing(object sender, FormClosingEventArgs e)
            {
                if (data != null)
                {
                    data.BeginLoadData();

                    data.Clear();

                    data.EndLoadData();

                    data.Dispose();

                    GC.SuppressFinalize(data);

                    GC.Collect(0);
                    GC.Collect(1);
                    GC.Collect(2);

                }
            }

            private DataTable data;

            private void InitializeDataTable()
            {
                if (null == data)
                {
                    data = new DataTable();
                    data.Columns.AddRange(new DataColumn[] { new DataColumn("ID"), new DataColumn("DateTime") });
                    for (int i = 0; i < 1000000; i++)
                        data.Rows.Add(i, DateTime.Now.ToString("yyyyMMdd HH:mm:ss"));
                }
            }

            private void DataTableForm_Load(object sender, EventArgs e)
            {

            }
        }


    I see you~http://hi.baidu.com/1987raymondMy Blog~~~
    2010年5月18日 2:11
    版主
  • 1)在.NET托管代码中,整个开销分配与回收是由NET统一管理的,这一点一般无需程序员考虑(相比C++考虑很周到)。

    2)至于说如果你时间很长,你应到考虑有必要把那么多数据一下子加载进来到DataSet或者DataTable吗?不如仿造Asp.Net,也来个分页处理吧:

    http://www.cnblogs.com/sayu115/archive/2007/10/12/922115.html

    2010年5月19日 8:39
    版主

全部回复

  • 你好!

          首先,不建议你把如此多的数据都加载到DataTable中,只加载需要的数据就可以了!

          其次,不建议你调用GC.Collect方法来强制执行垃圾回收,执行一次垃圾回收本身的性能开销就很大,包括遍历所有的根,构造可达对象图,为终止化可达链表中的对象执行终止化,“压内存”!CLR本身是有一定的算法来判断在何时执行这个操作性价比最好!你手动调用的时机很可能不合适!

          最后,垃圾回收操作是在单独的线程中执行的,所以即使你使用GC.Collect方法来强制垃圾收集,也不一定马上就看到效果,因为他要执行上面提到的那些工作,而且是在其他线程中进行,和操作系统的线程调度有一定关系的!


    周雪峰
    2010年5月18日 1:34
    版主
  • 你好  我新建了个测试窗体 是可以释放的 最开始打开窗体内存占用大道200多MB关闭后就只有40多MB了 如果最小化以下主窗体 那么则只有几MB了(所以可以让窗体最小化  再显示就可以快速减少内存)

    如果不添加回收那段代码 即便窗体关闭 内存也不会马上下降的,由此可见GC是发挥了作用的。

     public partial class DataTableForm : Form
        {
            public DataTableForm()
            {
                InitializeComponent();
                InitializeDataTable();
                this.FormClosing += new FormClosingEventHandler(DataTableForm_FormClosing);
            }

            void DataTableForm_FormClosing(object sender, FormClosingEventArgs e)
            {
                if (data != null)
                {
                    data.BeginLoadData();

                    data.Clear();

                    data.EndLoadData();

                    data.Dispose();

                    GC.SuppressFinalize(data);

                    GC.Collect(0);
                    GC.Collect(1);
                    GC.Collect(2);

                }
            }

            private DataTable data;

            private void InitializeDataTable()
            {
                if (null == data)
                {
                    data = new DataTable();
                    data.Columns.AddRange(new DataColumn[] { new DataColumn("ID"), new DataColumn("DateTime") });
                    for (int i = 0; i < 1000000; i++)
                        data.Rows.Add(i, DateTime.Now.ToString("yyyyMMdd HH:mm:ss"));
                }
            }

            private void DataTableForm_Load(object sender, EventArgs e)
            {

            }
        }


    I see you~http://hi.baidu.com/1987raymondMy Blog~~~
    2010年5月18日 2:11
    版主
  • 1)在.NET托管代码中,整个开销分配与回收是由NET统一管理的,这一点一般无需程序员考虑(相比C++考虑很周到)。

    2)至于说如果你时间很长,你应到考虑有必要把那么多数据一下子加载进来到DataSet或者DataTable吗?不如仿造Asp.Net,也来个分页处理吧:

    http://www.cnblogs.com/sayu115/archive/2007/10/12/922115.html

    2010年5月19日 8:39
    版主
  • 我是分页读取数据库的,要不然,一次性也不可能填充那么多条
    2010年5月19日 11:47
  • 咦?那为什么我这边释放不了的?难道跟我用datagridview绑定有关?
    2010年5月19日 11:48
  • 我是分页读取数据库的,要不然,一次性也不可能填充那么多条

    为什么不在数据库里面就分页了。即使是本地,把那么一大堆数据推进内存也浪费时间。
    2010年5月21日 5:09
  • 那部分数据需要读取到本地之后,我要导出成excel,然后同时也要显示在datagridview里面,所以我只能每次分页的从数据库中读取数据存放到本地
    2010年5月25日 15:52