在我的流式WCF应用程序中,我在我的服务中获得System.OutOfMemoryExceptions
大型消息(使用datareader查询> 7GB MSSQL表,消息甚至可能超过7GB),而小消息可以正常工作。我可以观察到DataReaderToExcelXml
执行期间内存使用量不断增长(见下文)。奇怪的是,它通常会快速增长到2GB,暂时保持在2GB + -1GB(1-5分钟),然后再次快速升至~6.5GB,这导致异常(机器有8GB内存)。在这一点上它向我看,好像Stream不再通过,而是缓冲。
我已经启用了跟踪日志记录,但似乎停止了异常。 DataReaderToExcelXml
函数调用是跟踪日志中的最后一个可见事件。
在WCF消息合同中,我确保消息仅包含Stream。在客户端,只需读取返回的流,将其写入文件流并进行处理。但是,当我得到异常时,我永远无法观察正在执行的客户端代码或正在写入的文件。
我已尝试在客户端和服务器端将maxBufferPoolSize
设置为零,如https://stackoverflow.com/a/595871/4166885所述。没有成功。
WCF服务端的流编写器功能:
Public Shared Function DataReaderToExcelXml(ByRef dr As SqlDataReader) As Stream
Dim ms As New MemoryStream
Dim tw As New IO.StreamWriter(ms)
For Each row As DbDataRecord In dr
'Embed row in ExcelXml, detailed function omitted
tw.write(row.toString()) 'row.toString is just a simplification
End While
tw.Flush()
dr.Close()
ms.Seek(0, SeekOrigin.Begin)
Return ms
End Function
Web.config绑定
<bindings>
<basicHttpBinding>
<binding receiveTimeout="24.00:00:00" sendTimeout="24.00:00:00"
maxBufferPoolSize="9223372036854775807" maxReceivedMessageSize="9223372036854775807"
messageEncoding="Mtom" transferMode="Streamed" bypassProxyOnLocal="True">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
App.config bindings
<binding name="BasicHttpBinding_IFileService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="24.00:00:00" sendTimeout="24.00:00:00"
allowCookies="false" bypassProxyOnLocal="true" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="8589934592" messageEncoding="Mtom"
textEncoding="utf-8" transferMode="Streamed">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="2147483647" />
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
编辑:在我的服务上使用.NET内存分析器我发现,越来越多的内存可以追溯到类型byte[]
。就个人而言,这对我没有任何意义,但也许这是有用的信息。
edit2:在检查System.OutOfMemoryException
时,我注意到ms.Capacity = ms.length = 1073741824 = 1GB时发生了这种情况。因此,在内存流将容量增加一倍之前。我仍然不确定,为什么w3wp首先消耗如此大量的内存,但现在显然内存流会触发异常。
答案 0 :(得分:1)
那么,阅读你的问题,我认为你的错误来源是关键。究竟错误在哪里?在运输中,还是在您的服务器中? 如果在DataReaderToExcel中引发异常,也许您可以考虑另一个想法(我认为它不是WCF问题): 到目前为止,我认为您在Windows窗体应用程序中会遇到同样的问题。
您需要内存,因此只能使用SqlDataReader填充它,您必须根据范围按块查询。
我们将开始计算&#34; TotalRecords&#34;:
SELECT COUNT(*)
FROM YOUR_TABLE
WHERE WATHEVER_YOU_WANT
例如,查询 10.000 记录的块,您有TotalRecords / 10.000页(查询)+1。 (例如:30.001行,每块10.000行= 4个查询)
迭代构建它们:
select top **10.000** * from
(SELECT TOP (100) PERCENT ROW_NUMBER() OVER (ORDER BY YOUR_TABLE_FIELD_1 DESC) ROW_PAGINATED, YOUR_TABLE_FIELD_1, YOUR_TABLE_FIELD_2 , ... , YOUR_TABLE_FIELD_N
FROM YOUR_TABLE
WHERE WATHEVER_YOU_WANT
ORDER BY YOUR_TABLE_FIELD_1 DESC
) YOUR_ALIAS
WHERE YOUR_ALIAS.ROW_PAGINATED BETWEEN min_records_per_page AND max_records_per_page
)
min_records_per_page AND max_records_per_page具有此值:
Query 1:
min_records_per_page= 1
max_records_per_page = 10000
Query 2:
min_records_per_page= 10001
max_records_per_page = 20000
...
Query N:
min_records_per_page= (N-1)* +1
max_records_per_page = TotalRecords
在每次迭代中,您将每个数据行映射到ExcelXml类。
这样做,假设您将处置您使用的对象,您将避免消耗所有内存。例如,您可以使用Function SetProcessWorkingSetSize每2次迭代。 在大量处理过的行之后释放内存:
Private Declare Auto Function SetProcessWorkingSetSize Lib "kernel32.dll" (ByVal procHandle As IntPtr, ByVal min As Int32, ByVal max As Int32) As Boolean
Dim Mem As Process
Mem = Process.GetCurrentProcess()
SetProcessWorkingSetSize(Mem.Handle, -1, -1)
然后,现在你有一个带有映射对象的数组。第1部分完成。
第2部分。您的客户端WCF可能会收到此数据。如果您要发送的数据准备就绪,那么请告诉我们您是否有问题。然后我们可以探索通信参数,然后我们会说&#34;增加那个参数,或者添加这个参数&#34;。
希望有所帮助