2011-06-29 61 views
1

我在执行SQL更新时引发的WinForms应用程序中出现System.OutOfMemory异常,我猜想。我该如何解决这个问题?在这种情况下,我使用SQLEXPRESS,在32位机器上尝试代码,以便ThreadPool在启动时具有默认的1023可用工作线程。线程池System.OutOfMemory执行SQL作业时出现异常

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进行较慢,较不频繁的请求。

+0

您从数据库请求了多少数据? – Peter

+0

为什么启动这么多的线程? –

+1

你真的需要这么多线程吗?也许你应该使用msmq和线程相当低的进程? – adt

回答

2

盲目地创建大量线程以使操作更快速并不是一个好的解决方案,并且几乎从不运行(除非运气可能)。请记住,每个线程都有自己的堆栈分配,默认情况下为1MB。所以如果你有1000个线程去使用1GB的RAM就像那样。

如果你点击了数据库,那么你可以并行执行的工作很可能会受到磁盘I/O的限制,所以抛出更多的线程可能会让它变得更糟。

另请注意,异步操作在线程池线程上执行,如果将它们与自己的工作绑定在一起,则可能会遇到问题以使这些操作挨饿(意味着它们可能永远不会或很晚执行)。线程池被设计为只运行短暂的任务。如果您需要长时间运行任务,请使用其他线程池(例如SmartThreadPool)或创建自己的一组线程来处理工作。

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

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

相关问题