Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
依赖.NET自动垃圾收集器是一种不好的做法吗?_.net_Garbage Collection - Fatal编程技术网

依赖.NET自动垃圾收集器是一种不好的做法吗?

依赖.NET自动垃圾收集器是一种不好的做法吗?,.net,garbage-collection,.net,Garbage Collection,可以创建大量内存密集型对象,然后放弃对它们的引用。例如,我可能想从数据库下载并操作一些数据,我将进行100次单独的下载和处理迭代。我可以声明一个DataTable变量一次,对于每个查询,使用构造函数将其重置为一个新的DataTable对象,在内存中放弃旧的DataTable对象 DataTable类具有释放其使用的内存的简单内置方法,包括Rows.Clear()和.Dispose()。因此,在将变量设置为新的DataTable对象之前,我可以在每次迭代结束时执行此操作。或者我可以忘记它,让CLR

可以创建大量内存密集型对象,然后放弃对它们的引用。例如,我可能想从数据库下载并操作一些数据,我将进行100次单独的下载和处理迭代。我可以声明一个DataTable变量一次,对于每个查询,使用构造函数将其重置为一个新的DataTable对象,在内存中放弃旧的DataTable对象

DataTable类具有释放其使用的内存的简单内置方法,包括Rows.Clear()和.Dispose()。因此,在将变量设置为新的DataTable对象之前,我可以在每次迭代结束时执行此操作。或者我可以忘记它,让CLR垃圾收集器为我做这件事。垃圾收集器似乎非常有效,因此最终结果应该是相同的。当您不需要内存重的对象时,显式地处理它们是“更好的”(但添加代码来完成这一点),还是仅仅依靠垃圾收集器来为您完成所有工作(您受GC算法的支配,但您的代码更小)

根据要求,下面是说明回收数据表变量示例的代码:

    // queryList is list of 100 SELECT queries generated somewhere else.
    // Each of them returns a million rows with 10 columns.
    List<string> queryList = GetQueries(@"\\someserver\bunch-o-queries.txt");
    DataTable workingTable;

    using (OdbcConnection con = new OdbcConnection("a connection string")) {
        using (OdbcDataAdapter adpt = new OdbcDataAdapter("", con)) {
            foreach (string sql in queryList) {
                workingTable = new DataTable();  // A new table is created. Previous one is abandoned
                adpt.SelectCommand.CommandText = sql;
                adpt.Fill(workingTable);
                CalcRankingInfo(workingTable);
                PushResultsToAnotherDatabase(workingTable);
                // Here I could call workingTable.Dispose() or workingTable.Rows.Clear()
                // or I could do nothing and hope the garbage collector cleans up my
                // enormous DataTable automatically.
            }   
        }
    }
//queryList是在其他地方生成的100个SELECT查询的列表。
//它们每个都返回100万行10列。
List queryList=getquerys(@“\\someserver\bunch-o-querys.txt”);
数据表工作表;
使用(OdbcConnection con=newodbcconnection(“连接字符串”)){
使用(OdbcDataAdapter adpt=新OdbcDataAdapter(“,con)){
foreach(queryList中的字符串sql){
workingTable=new DataTable();//将创建一个新表。放弃上一个表
adpt.SelectCommand.CommandText=sql;
调整填充(工作台);
CalcRankingInfo(工作台);
将结果推送到另一个数据库(工作表);
//在这里,我可以调用workingTable.Dispose()或workingTable.Rows.Clear()
//或者我什么也做不了,希望垃圾收集器能清理我的垃圾
//自动生成庞大的数据表。
}   
}
}

好的,是时候把事情弄清楚一点了(因为我原来的帖子有点混乱)

IDisposable与内存管理无关
IDisposable
允许对象清除它可能持有的任何本机资源。如果对象实现了
IDisposable
,则应确保在使用完
块后使用
或调用
Dispose()

至于定义内存密集型对象,然后丢失对它们的引用,垃圾收集器就是这样工作的。这是件好事。让它发生,让垃圾收集器完成它的工作

…因此,要回答您的问题,不。依赖.NET垃圾收集器并不是一种不好的做法。事实恰恰相反。

@Justin

…因此,要回答您的问题,不。依赖.NET垃圾收集器并不是一种不好的做法。事实恰恰相反

依靠GC为您清理是一种可怕的做法。不幸的是,你建议这样做。这样做很可能会导致内存泄漏,是的,在.NET中至少有22种方法可以“泄漏内存”。我曾在大量客户机上工作,诊断托管和非托管内存泄漏,为它们提供解决方案,并在多个.NET用户组上介绍了高级GC内部以及如何从GC和CLR内部进行内存管理

@作品: 应该对DataTable调用Dispose(),并在循环结束时显式将其设置为null。这会显式地告诉GC您已经完成了对它的操作,并且不再有对它的根引用。由于DataTable的大小很大,所以它被放置在LOH上。不这样做很容易分割LOH,导致OutOfMemoryException。记住,LOH永远不会被压实

有关更多详情,请参阅我在

@Henk-IDisposable和内存管理之间存在关系;IDisposable允许半显式地释放资源(如果正确实现)。资源总是有某种类型的托管内存,通常是与之相关联的非托管内存

关于Dispose()和IDisposable,需要注意以下几点:

  • IDisposable提供了对托管和非托管内存的处置。非托管内存的处置应该在Dispose方法中完成,并且应该为IDisposable实现提供终结器

  • GC不会为您调用Dispose

  • 如果不调用Dispose(),GC会将其发送到终结 队列,并最终再次到达f-可达队列。定稿 使对象在2个集合中生存,这意味着它将 如果在Gen0中,则升级到Gen1;如果在Gen1中,则升级到Gen2。 在您的例子中,对象位于LOH上,因此它会一直存在,直到完全恢复 GC(所有世代加上LOH)执行两次, 在“Health.NET”应用程序下,一个完整的集合是 每100个系列中约有1个。因为有很多 根据您的实现,LOH堆和GC上的压力是完全的 GC将更频繁地开火。这对性能是不可取的 因为完整GC需要更多的时间来完成。然后呢 它还依赖于您运行的GC类型以及 您正在使用LatencyModes(对此要非常小心)。即使 您正在运行后台GC(这已取代CLR中的并发GC) 4.0),临时集合(Gen0和Gen1)仍然阻塞/挂起线程。这意味着在此期间无法执行任何分配 时间您可以使用PerfMon来监视