Need help resolving an error when WCF service returns DataTable: OutOfMemoryException

青春壹個敷衍的年華 提交于 2020-01-14 04:00:31

问题


I have a WCF service running that is attempting to return a DataTable. The service method uses a SqlDataReader, and then uses DataTable.Load() to get that data into the DataTable it intends to return.

Problem: when the service method returns a large table (I'll define this in a moment), I get these exceptions in the debug output (they do not cripple the service):

A first chance exception of type 'System.OutOfMemoryException' occurred in SMDiagnostics.dll

A first chance exception of type 'System.InsufficientMemoryException' occurred in SMDiagnostics.dll

Definition of "Large": the returned record set in my testing contains 286760 records and when this table is exported out to text, it's roughly 800MB in size. I know this is all relative, so that might all be meaningless. Mostly, I point this out because this seems rather small to me to be throwing memory exceptions, especially in light of the fact that the development machine on which I'm testing has 8GB of memory. Again, it's all relative, and perhaps irrelevant, but I'm trying to provide enough information.

Here is my connection code:

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);

Note, that we're using the Buffered transfer mode. I'm considering the Streamed alternative, but that will impose a radical structure change to the rest of the code...not something I want to do if there's a solution within the current model. I point back to the fact that I just don't think I'm pushing inordinate amounts of data.

This connection is established as part of the creation of a Sql class object (my class). The iChannel and svcCon objects are disposed of together when the Sql.Dispose() method is invoked (because we create these Sql objects with a using block).

Here's the Sql.Dispose() method that my using blocks should be triggering (in case it matters):

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(); }
}

In summary, I am creating a WCF communication channel, which in turn creates a SqlConnection. Using that, we fire off SQL calls. All of this is then disposed of as quickly as possible. We do not hang onto these connections for any longer than is necessary to perform the needed database operations. And there are very rare cases where these things are not created within using blocks, meaning that I am quite sure we are cleaning up properly. Unless, of course, someone sees a problem with my Dispose() method.

Any advice is appreciated. I can provide more code as requested.

Some additional information: here is the stack trace I receive when debugging the client and stepping into the server code to watch what happens when it attempts to return the 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'

回答1:


Please verify dataContractSerializer attribute under behaviors section and increase the value to a greater value.

Also check readerQuotas section as well as maxBufferPoolSize, maxBufferSize and maxReceivedMessageSize attributes.




回答2:


Change your transfermode to streamed both web config and other config... u cant change web config transfermode unless you deploy it in your IIS



来源:https://stackoverflow.com/questions/18149465/need-help-resolving-an-error-when-wcf-service-returns-datatable-outofmemoryexce

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!