在WCF服务返回DataTable时需要帮助解决错误:OutOfMemoryException

我有一个正在尝试返回DataTable的WCF服务。 service方法使用SqlDataReader ,然后使用DataTable.Load()将该数据输入到它想要返回的DataTable

问题:当服务方法返回一个大表时(我稍后会定义它),我在调试输出中得到这些exception(它们不会削弱服务):

SMDiagnostics.dll中出现类型为“System.OutOfMemoryException”的第一次机会exception

SMDiagnostics.dll中发生了’System.InsufficientMemoryException’类型的第一次机会exception

“大”的定义:我测试中返回的记录集包含286760条记录,当该表导出为文本时,大小约为800MB。 我知道这都是相对的,所以这可能都是毫无意义的。 大多数情况下,我指出这一点是因为对于我来说,抛出内存exception似乎相当小,特别是考虑到我正在测试的开发机器有8GB内存这一事实。 同样,它都是相对的,也许是无关紧要的,但我正在努力提供足够的信息。

这是我的连接代码:

 NetTcpBinding netBind = new NetTcpBinding(); netBind.Security.Mode = SecurityMode.Transport; netBind.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows; netBind.MaxReceivedMessageSize = Int32.MaxValue; netBind.MaxBufferSize = Int32.MaxValue; netBind.MaxBufferPoolSize = 0; netBind.MaxConnections = 300; netBind.ListenBacklog = 300; netBind.ReaderQuotas = XmlDictionaryReaderQuotas.Max; netBind.PortSharingEnabled = true; netBind.OpenTimeout = new TimeSpan(0, 0, RegistryValues.DatabaseTimeout); netBind.CloseTimeout = new TimeSpan(0, 0, RegistryValues.DatabaseTimeout); netBind.ReceiveTimeout = new TimeSpan(0, 5, 0); netBind.SendTimeout = new TimeSpan(0, 5, 0); netBind.ReliableSession.InactivityTimeout = new TimeSpan(long.MaxValue); netBind.TransferMode = TransferMode.Buffered; uriBuilder = new UriBuilder("net.tcp", connServer, (connPort == -1 ? RegistryValues.ServerPort : connPort), "Data"); epAddress = new EndpointAddress(uriBuilder.Uri); ChannelFactory iChannel = new ChannelFactory(netBind, epAddress); iChannel.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Identification; IData svcCon = iChannel.CreateChannel(); ((IClientChannel)svcCon).OperationTimeout = new TimeSpan(long.MaxValue); 

注意,我们正在使用Buffered传输模式。 我正在考虑Streamed替代方案,但这将对其余代码强加一个根本性的结构改变……如果在当前模型中有解决方案,我不想做的事情。 我再次回到这样一个事实:我不认为我在推动过多的数据。

此连接是作为创建Sql类对象(我的类)的一部分建立的。 调用Sql.Dispose()方法时, iChannelsvcCon对象将一起处理(因为我们using块创建这些Sql对象)。

这是我的using块应该触发的Sql.Dispose()方法(如果它很重要):

 public void Dispose() { if (this != null && this.connection.State == ConnectionState.Open) ClearConnectionPool(); try { if (iChannel.State != CommunicationState.Faulted) iChannel.Close(); } catch { iChannel.Abort(); } try { if (((IClientChannel)svcCon).State != CommunicationState.Faulted) ((IClientChannel)svcCon).Close(); } catch { ((IClientChannel)svcCon).Abort(); } } 

总之,我正在创建一个WCF通信通道,该通道又创建一个SqlConnection 。 使用它,我们启动SQL调用。 然后尽快处理所有这些。 我们不会将这些连接挂起到执行所需数据库操作所需的时间。 并且在极少数情况下,这些东西不是在using块中创建的,这意味着我很确定我们正在正确清理。 当然,除非有人看到我的Dispose()方法出现问题。

任何建议表示赞赏。 我可以按要求提供更多代码。

一些附加信息:这是我在调试客户端时收到的堆栈跟踪,并进入服务器代码以查看尝试返回DataTable时发生的情况:

 A first chance exception of type 'System.OutOfMemoryException' occurred in SMDiagnostics.dll A first chance exception of type 'System.InsufficientMemoryException' occurred in SMDiagnostics.dll A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll Step into: Stepping over method without symbols 'System.ServiceModel.Dispatcher.MessageRpc.Process' A first chance exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.dll Step into: Stepping over method without symbols 'System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump' A first chance exception of type 'System.IO.IOException' occurred in System.dll Step into: Stepping over method without symbols 'System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest' Step into: Stepping over method without symbols 'System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump' A first chance exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.dll Step into: Stepping over method without symbols 'System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame' Step into: Stepping over method without symbols 'System.ServiceModel.AsyncResult.Complete' A first chance exception of type 'System.ServiceModel.CommunicationException' occurred in mscorlib.dll Step into: Stepping over method without symbols 'System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame' Step into: Stepping over method without symbols 'System.ServiceModel.AsyncResult.Complete' A first chance exception of type 'System.ServiceModel.CommunicationObjectFaultedException' occurred in System.ServiceModel.dll Step into: Stepping over method without symbols 'System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame' Step into: Stepping over method without symbols 'System.Net.LazyAsyncResult.Complete' A first chance exception of type 'System.ServiceModel.CommunicationObjectFaultedException' occurred in mscorlib.dll Step into: Stepping over method without symbols 'System.Net.Security.NegotiateStream.ProcessFrameBody' A first chance exception of type 'System.ServiceModel.CommunicationObjectFaultedException' occurred in System.ServiceModel.dll Step into: Stepping over method without symbols 'System.Net.Security.NegotiateStream.ReadCallback' Step into: Stepping over method without symbols 'System.Net.FixedSizeReader.CheckCompletionBeforeNextRead' Step into: Stepping over method without symbols 'System.Net.FixedSizeReader.ReadCallback' Step into: Stepping over method without symbols 'System.ServiceModel.AsyncResult.Complete' Step into: Stepping over method without symbols 'System.ServiceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame' Step into: Stepping over method without symbols 'System.Threading._IOCompletionCallback.PerformIOCompletionCallback' 

请validationbehavior行为部分下的dataContractSerializer属性,并将值增加到更大的值。

还要检查readerQuotas部分以及maxBufferPoolSize,maxBufferSize和maxReceivedMessageSize属性。

将您的transfermode更改为流配置Web配置和其他配置…除非您在IIS中部署它,否则无法更改Web配置传输模式