我有一个WCF服务正在尝试返回DataTable
。服务方法使用SqlDataReader
,然后使用DataTable.Load()
将数据输入它打算返回的DataTable
。
问题:当服务方法返回一个大表时(我稍后会定义它),我在调试输出中得到这些异常(它们不会削弱服务):
SMDiagnostics.dll中出现类型为“System.OutOfMemoryException”的第一次机会异常
SMDiagnostics.dll中发生了'System.InsufficientMemoryException'类型的第一次机会异常
“大”的定义:我测试中返回的记录集包含286760条记录,当该表导出为文本时,大小约为800MB。我知道这都是相对的,所以这可能都是毫无意义的。大多数情况下,我指出这一点,因为对于我来说,抛出内存异常似乎相当小,特别是考虑到我正在测试的开发机器有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<IData> iChannel = new ChannelFactory<IData>(netBind, epAddress);
iChannel.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Identification;
IData svcCon = iChannel.CreateChannel();
((IClientChannel)svcCon).OperationTimeout = new TimeSpan(long.MaxValue);
请注意,我们正在使用Buffered
传输模式。我正在考虑使用Streamed
替代方案,但这会对代码的其余部分进行彻底的结构更改...如果在当前模型中有解决方案,那么我不想做什么。我回想一下这样一个事实:我不认为我在推动过多的数据。
此连接是作为创建Sql
类对象(我的类)的一部分而建立的。当调用iChannel
方法时,svcCon
和Sql.Dispose()
对象被一起处理(因为我们用Sql
块创建这些using
对象)。
这是我的Sql.Dispose()
块应该触发的using
方法(如果它很重要):
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'
请验证behavior行为部分下的dataContractSerializer属性,并将值增加到更大的值。
还要检查readerQuotas部分以及maxBufferPoolSize,maxBufferSize和maxReceivedMessageSize属性。
将您的transfermode更改为流式传输web配置和其他配置...除非您在IIS中部署它,否则无法更改Web配置传输模式