【问题标题】:Need help resolving an error when WCF service returns DataTable: OutOfMemoryException当 WCF 服务返回 DataTable: OutOfMemoryException 时需要帮助解决错误
【发布时间】:2013-08-09 14:46:24
【问题描述】:

我有一个 WCF 服务正在运行,它试图返回 DataTable。服务方法使用SqlDataReader,然后使用DataTable.Load() 将该数据获取到它打算返回的DataTable。

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

在 SMDiagnostics.dll 中发生了“System.OutOfMemoryException”类型的第一次机会异常

在 SMDiagnostics.dll 中出现“System.InsufficientMemoryException”类型的第一次机会异常

“Large”的定义:我的测试返回的记录集包含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() 方法时被一起处理(因为我们使用 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() 方法有问题。

感谢任何建议。我可以按要求提供更多代码。

一些附加信息:这是我在调试客户端并单步进入服务器代码时收到的堆栈跟踪,以观察当它尝试返回 @987654340 时会发生什么@:

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'

【问题讨论】:

  • 机器的位数是多少? 32 还是 64 ?如果它是 32,则可能您的连续内存不足
  • @Menahem 平台目标 = x86。机器是 Windows 7 Pro 64bit。
  • 不确定,但我认为以 x86 为目标将使您的进程运行 32 位模式,因此可能会遇到连续的进程地址空间中断。你能尝试运行纯 64 吗?
  • 为什么将 MaxBufferPoolSize 属性设置为 0?
  • @Tim 很好。那是以前的最大值,但我在测试我读过的东西时改变了它。有人建议这将强制每次获取新缓冲区。没有任何区别。

标签: c# sql-server wcf out-of-memory


【解决方案1】:

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

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

【讨论】:

  • 我没有dataContractSerializer。什么价值?读者配额?你假设这是基于网络的吗?如果是这样,那是不正确的。
  • 此链接可能有帮助? stackoverflow.com/questions/884235/…
  • 谢谢,但很遗憾没有。具体来说,该问题涉及解决特定的消息配额超出问题,而我没有。我得到一个更广泛的“内存不足”异常,我不知道它来自哪里。
  • @DonBoitnott 你说你不知道异常来自哪里。您是否尝试过进行进程转储(第一次)?也许堆里会有更多的数据。
  • @Menahem 我不得不恳求我不知道如何做这样的事情。我所知道的是,在调试服务时,我到达return dt; (dt = DataTable object) 行,然后在下一步中抛出异常。所以目前我的服务代码将表格交给 WCF 管道以返回。
【解决方案2】:

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

【讨论】:

  • 这不是网络服务,它是局域网。简单地改用流媒体会带来灾难性的后果,而不会改变行为以使其发挥作用。不是轻按开关那么简单。
猜你喜欢
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 2018-07-31
  • 2021-09-10
相关资源
最近更新 更多