WPF WCF MVVM OutOfMemoryException

3
我正在开发一款WCF-WPF应用程序。在异步XamDataGrid上经常会遇到此错误。尝试进行WCF调用并填充网格。我最初认为这与从WCF返回的大量数据有关,并通过仅调用一个类别来使调用返回较小的数据块。这个错误是随机出现的,不总是在同一组数据上。可以在15-20次尝试中重现。
我正在运行Windows XP(32位),双核,带有4GB的内存。当引发此异常时,客户端机器只使用约2GB的RAM,在服务器上W3WP仅使用800MB(6GB的其中3个核心。服务器上的总内存使用约为2GB)。
只有在XP机器上才会发生这种情况。在Windows 7上没有遇到过此错误。
请指导我如何解决此问题。
提前感谢您。
Event Viewer Logs this Message:
Event Type: Error
Event Source:   .NET Runtime 2.0 Error Reporting
Event Category: None
Event ID:   5000
Date:       10/13/2010
Time:       10:50:07 AM
User:       N/A
Computer:   COMP-DC7800
Description:
EventType clr20r3, P1 appname.exe, P2 2.0.0.21872, P3 4cb0a1b1, P4 mscorlib, P5 2.0.0.0, P6 492b834a, P7 35df, P8 45, P9 system.outofmemoryexception, P10 NIL.

以下是异常详细信息:
System.OutOfMemoryException was unhandled
Message="Exception of type 'System.OutOfMemoryException' was thrown."
Source="mscorlib"
StackTrace:
   at System.IO.MemoryStream.set_Capacity(Int32 value)
   at System.IO.MemoryStream.EnsureCapacity(Int32 value)
   at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at System.Xml.XmlMtomReader.MimePart.GetBuffer(Int32 maxBuffer, Int32& remaining)
   at System.Xml.XmlMtomReader.Initialize(Stream stream, String contentType, XmlDictionaryReaderQuotas quotas, Int32 maxBufferSize)
   at System.Xml.XmlMtomReader.SetInput(Stream stream, Encoding[] encodings, String contentType, XmlDictionaryReaderQuotas quotas, Int32 maxBufferSize, OnXmlDictionaryReaderClose onClose)
   at System.Xml.XmlMtomReader.SetInput(Byte[] buffer, Int32 offset, Int32 count, Encoding[] encodings, String contentType, XmlDictionaryReaderQuotas quotas, Int32 maxBufferSize, OnXmlDictionaryReaderClose onClose)
   at System.ServiceModel.Channels.MtomMessageEncoder.MtomBufferedMessageData.TakeXmlReader()
   at System.ServiceModel.Channels.BufferedMessageData.DoTakeXmlReader()
   at System.ServiceModel.Channels.BufferedMessageData.GetMessageReader()
   at System.ServiceModel.Channels.MessageHeaders.GetBufferedMessageHeaderReaderAtHeaderContents(IBufferedMessageData bufferedMessageData)
   at System.ServiceModel.Channels.MessageHeaders.GetBufferedMessageHeaderReader(IBufferedMessageData bufferedMessageData, Int32 bufferedMessageHeaderIndex)
   at System.ServiceModel.Channels.MessageHeaders.GetReaderAtHeader(Int32 headerIndex)
   at System.ServiceModel.Channels.WsrmMessageInfo.Get(MessageVersion messageVersion, ReliableMessagingVersion reliableMessagingVersion, IChannel channel, ISession session, Message message, Boolean csrOnly)
   at System.ServiceModel.Channels.ReliableDuplexSessionChannel.HandleReceiveComplete(IAsyncResult result)
   at System.ServiceModel.Channels.ReliableDuplexSessionChannel.OnReceiveCompletedStatic(IAsyncResult result)
   at System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
   at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
   at System.ServiceModel.Channels.ReliableChannelBinder`1.InputAsyncResult`1.OnInputComplete(IAsyncResult result)
   at System.ServiceModel.Channels.ReliableChannelBinder`1.InputAsyncResult`1.OnInputCompleteStatic(IAsyncResult result)
   at System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
   at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
   at System.ServiceModel.Channels.InputQueue`1.AsyncQueueReader.Set(Item item)
   at System.ServiceModel.Channels.InputQueue`1.Dispatch()
   at System.ServiceModel.Channels.InputQueue`1.OnDispatchCallback(Object state)
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke2()
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.OnSecurityContextCallback(Object o)
   at System.Security.SecurityContext.Run(SecurityContext securityContext, ContextCallback callback, Object state)
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke()
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ProcessCallbacks()
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.CompletionCallback(Object state)
   at System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
   at System.ServiceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

你有检查过你的应用程序是否存在内存泄漏吗? - decyclone
@Bhuvan 1)内存是逐渐增加直到耗尽还是一切正常,突然在一个WCF调用的范围内发生?2)你的XML有多大? - Aliostad
@Aliostad... 是的,客户端的内存会逐渐增加...对于每个服务调用...服务使用MTOM编码器并返回约1MB(大致如此)的数据量,这些数据本质上是业务对象列表。有时候内存会被释放...当我在进程资源管理器中观察时...但是,模式一致,即在50到60个服务调用后客户端会崩溃。 - Bhuvan
@Buhvan 我假设它是一个 WPF/金融项目,所以您可能会在其中进行一些聪明的图形处理。您是否在其中加载、绘制或渲染任何图像? - Aliostad
每次服务调用后我都在调用GC.Collect(),并使用“Process Explorer”监视内存使用情况,但应用程序仍会崩溃。 - Bhuvan
显示剩余2条评论
3个回答

1

一般而言,OutOfMemory异常可能会因为很多原因发生,特别是在Web应用程序中。

首先,如果您正在运行IIS,则有特定于IIS的设置来限制内存,请参见此处:http://blogs.msdn.com/b/pfedev/archive/2009/01/22/memory-based-recycling-in-iis-6-0.aspx

根据您的配置、池等,这些限制可能不适用于.NET Web应用程序。

现在,在ASP.NET中,还有一个名为memoryLimit的设置,位于machine.config文件中,它指定了工作进程在ASP.NET启动新进程并重新分配现有请求之前可以消耗的最大允许内存大小(作为总系统内存的百分比)。

默认值为60%,在2G机器上相当于1.2G。

然而,无论你如何配置,32位机器上ASP.NET应用程序的实际限制为800M,详细解释请参见此处:理解ASP.Net内存

避免这种情况的解决方案是改变系统工作方式并将其分成更小的部分。

这就是为什么默认情况下,WCF已经被精心配置了许多限制(请参见此处的详细列表:http://weblogs.asp.net/paolopia/archive/2008/03/23/wcf-configuration-default-limits-concurrency-and-scalability.aspx)......几乎每个开发人员都会在发现它后立即进行更改和最大化利用 :-)。


问题出在WCF客户端上。服务正常运行数周,没有任何问题,内存使用率稳定在约1GB左右。可能是因为我为双向通信托管了客户端会话的静态引用。但现在这不是问题所在。该应用程序是WCF-WPF-MVVM Windows客户端。 - Bhuvan
1
客户端或服务器,在32位XP机器上,.NET进程的实际限制是大约800M,原因与之前解释的相同。另一个链接:https://dev59.com/_nNA5IYBdhLWcg3wgeEd。WPF / MVVM可能与您的问题无关。您需要改变构建WCF服务接口的方式。 - Simon Mourier

0

你无法在32位操作系统中利用那4GB的内存。

http://chris.pirillo.com/32-bit-windows-and-4gb-of-ram/

如果您的应用程序在使用过程中消耗越来越多的内存,您可能需要查看内存管理。考虑为具有非托管资源的类实现IDisposable接口。此外,在使用完对象后避免保留对它们的引用。事件对此尤其不利。 C#中的事件如何导致内存泄漏,弱引用如何帮助缓解? 您还可以考虑将流式传输到临时文件而不是流式传输到内存中。

1
@感谢邪恶鸽子{感谢一个邪恶的鸽子有点不舒服...可能会冒犯大多数宗教 :)..你应该改名为天使鸽子}..我使用VS2010 Profiler(真是太棒了)检查了由于绑定、引用和“失败的WPF绑定”而导致的泄漏,这是非常小的,不到2MB,我不确定这是否导致了崩溃。在邪恶的Dr Watson出现之前,我看到的峰值是600MB,应该还有其他原因。 - Bhuvan

0
感到欣慰,找到了答案,原来是微软把它搞砸了... :). 这个谴责几乎挽救了我的工作... 这是个故事...
WCF 的默认消息大小为 64kb。在 MSDN 上找不到这样做的原因...所以当我们需要将最大消息大小更改为任何我们想要的大小时。问题是 LOH 的阈值 是 85000b。如果消息大小超过了这个值,对象就会被放置在 LOH 中,您的分析器会显示已收集对象...但是当您在 Sysinternals Process Explorer 中看到 LOH 大小时,在进程属性窗口中,您仍然会看到内存使用正在增加。在约 800MB 左右,我们强大的 Dr Watson 就会出现,并将此应用程序踢掉。显然,这是 WCF 和 .net 2.0 中已知的问题。

.net 4.0 中问题仍然存在,但是微软发布了一个快速修复程序。Sysinternals Process explorer 是帮助诊断此问题的工具。请参见屏幕截图。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接