线程池System.OutOfMemory执行SQL作业时出现异常

时间:2011-06-29 20:41:13

标签: c# winforms .net-4.0 sql-server-express threadpool

我一直在WinForms应用程序中获取System.OutOfMemory异常,我猜这是在做SQL更新时引发的。我该如何解决这个问题?在这种情况下,我正在使用SQLEXPRESS,在32位机器上尝试代码,因此ThreadPool在启动时具有默认的1023可用工作线程。

MyClass myClass = new MyClass();

for (int i = 0; i < 1000000; i++)
{              
    ThreadPool.QueueUserWorkItem(new WaitCallback(Foo), myClass);
}

private void Foo(object state)
{
    //Some Stuff and SQL UPDATE
}

当应用程序启动时,ThreadPool以8个线程开始,并开始增加分配的线程号以执行该作业。不久之后,它以200个线程为例,不再处理它,发出System.OutOfMemory异常。当我检查堆栈跟踪时,我可以看到该方法的SQL操作中发生异常。我该怎么办?我是否需要增加数据库的缓冲区大小?我不希望顺便限制ThreadPools的最大大小,或者尝试使用Thread.Sleep()来减慢对DB的请求。

1 个答案:

答案 0 :(得分:2)

盲目地创建大量线程以使操作更快,这不是一个好的解决方案,几乎从不工作(除非运气可能)。请记住,每个线程都会分配自己的堆栈,我认为默认情况下为1MB。因此,如果您获得1000个线程,那将使用1GB的RAM。

如果你点击了数据库,那么你可以并行完成的工作很可能受到磁盘I / O的限制,因此在它上面添加更多线程可能会使它变得更糟。

还要注意,在线程池线程上执行异步操作,如果你将它们与你自己的工作联系在一起,你可能会遇到问题,使这些操作陷入困境(意味着它们可能永远不会或很晚执行)。线程池旨在仅运行短期任务。如果您需要长时间运行的任务,那么使用不同的线程池(例如SmartThreadPool)或创建自己的线程集来处理工作。

根据您的SQL操作,您可能遇到大对象堆碎片问题。大于85.000字节的对象被放置在未被压缩的LOH上,并且您可能遇到意外的OOM欺骗。因此,请检查您是否正在创建大型数组或对象列表。

否则:使用debugging tools for windows进行内存转储,并查看围绕吃掉所有内存的设置对象,以及保存它们的引用。或者,您可以使用.NET内存分析器,但大多数非常有用的内存分析器不是免费的(但它们通常会带有X天评估期)。