1

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'
Community
  • 1
  • 1
DonBoitnott
  • 10,787
  • 6
  • 49
  • 68
  • whats the bitness of the machine ? 32 or 64 ? if it`s 32 maybe you are running out of contiguous memory – Menahem Aug 09 '13 at 14:49
  • @Menahem Platform Target = x86. Machine is Windows 7 Pro 64bit. – DonBoitnott Aug 09 '13 at 14:50
  • not sure, but i think targeting x86 will have your process running 32 bit mode, and thus may run into the contiguous process address space outage. can you try running pure 64 ? – Menahem Aug 09 '13 at 14:55
  • Why did you set the MaxBufferPoolSize property to 0? – Tim Aug 10 '13 at 01:13
  • @Tim Good catch. That was at max before, but I changed it while testing things I'd read about. Someone had suggested that that would force new buffers every fetch. Didn't make any difference. – DonBoitnott Aug 10 '13 at 21:15

2 Answers2

0

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.

PradeepGB
  • 314
  • 2
  • 10
  • I have no `dataContractSerializer`. What value? ReaderQuotas? Are you assuming this is web-based? If so, that is incorrect. – DonBoitnott Aug 12 '13 at 11:49
  • This link might help ? http://stackoverflow.com/questions/884235/wcf-how-to-increase-message-size-quota – PradeepGB Aug 12 '13 at 12:10
  • Thank you, but unfortunately it does not. Specifically, that question dealt solving a specific message quota exceedance, which I do not have. I am getting a more broad "out of memory" exception, and I have no idea where it is coming from. – DonBoitnott Aug 12 '13 at 12:31
  • @DonBoitnott you said you don't know where the exception is coming from. have you tried taking a process dump (on first chance) ? maybe there will be more data in the heap. – Menahem Aug 12 '13 at 20:02
  • @Menahem I have to plead ignorance on how to do such a thing. All I know for certain is that while debugging the service, I get to the line `return dt;` (dt = `DataTable` object) and on next step, an exception is thrown. So it's at the moment my service code hands the table off to the WCF pipeline to be returned. – DonBoitnott Aug 12 '13 at 20:04
  • @DonBoitnott , check out [this](http://stackoverflow.com/a/5819084/488699) answer, it`s a good start. still , if OOME is indeed the problem, the solution will probably be to change implementation. – Menahem Aug 13 '13 at 07:45
  • @Menahem "Change implementation": would that be defined as alter everything to support streaming instead of buffered transfer mode? – DonBoitnott Aug 13 '13 at 10:52
  • @DonBoitnott :) can`t say for sure. if i could, i would be writing an answer not a comment. my point is, having a good understanding of the problem might help. – Menahem Aug 13 '13 at 13:49
0

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

Angelo
  • 335
  • 4
  • 10
  • This is not a web service, it's LAN. And simply changing to streaming has disastrous consequences without altering behaviors to make that work. It is not so simple as flicking a switch. – DonBoitnott Aug 13 '13 at 10:51