【问题标题】:Why aren't these WCF related resources cleaned up?为什么不清理这些 WCF 相关资源?
【发布时间】:2009-10-28 21:33:19
【问题描述】:

这是我的场景:

  1. 启动我的测试程序并立即进入调试器 (WinDBG)
  2. 获取 !DumpHeap -stat 并观察任何地方都没有 System.Net* 或 System.Xml* 对象
  3. 创建我的 WCF 客户端,发出 WCF 请求
  4. 关闭 WCF 客户端并强制 GC。
  5. 使用 !DumpHeap -stat 观察,内存中仍有大量 System.Net*、System.Xml* 对象。

因此,根据我在第 5 步中的观察,WCF 似乎没有正确清理(或者更有可能我遗漏了一些东西)。为什么是这样?我怎样才能回收这些不应该在这里的对象占用的内存?

这是我的测试代码...

class Program
{
    static void Main(string[] args)
    {
        Debugger.Break();
        // !DumpHeap -stat here indicates no System.Net* or System.Xml* objects


        BasicHttpBinding binding = new BasicHttpBinding();
        binding.Security.Mode = BasicHttpSecurityMode.None;
        binding.UseDefaultWebProxy = false;
        WcfClient client = new WcfClient(
            binding, new EndpointAddress("http://myserver.com/service.svc"));
        client.Endpoint.Binding = binding;
        client.GetChain(new GetChainType()); // WCF call

        // my ineffective clean up code
        client.Close();
        client = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();


        // !DumpHeap -stat here indicates many System.Net* or System.Xml* objects

        Console.WriteLine("Request complete, press enter to quit");
        Console.ReadLine();
    }
}

附:这是我的 !FinalizeQueue 结果...不确定这是否相关

0:010> !FinalizeQueue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 1 finalizable objects (000000001b1527f8->000000001b152800)
generation 1 has 81 finalizable objects (000000001b152570->000000001b1527f8)
generation 2 has 0 finalizable objects (000000001b152570->000000001b152570)
Ready for finalization 0 objects (000000001b152800->000000001b152800)
Statistics:
              MT    Count    TotalSize Class Name
000007fef033d078        1           32 Microsoft.Win32.SafeHandles.SafePEFileHandle
000007fef0326ab0        1           32 System.Security.Cryptography.SafeProvHandle
000007fef0326680        1           32 Microsoft.Win32.SafeHandles.SafeTokenHandle
000007feef7a2c18        1           32 Microsoft.Win32.SafeHandles.SafeProcessHandle
000007feef7a2b78        1           32 Microsoft.Win32.SafeHandles.SafeFileMapViewHandle
000007feef7a2ad8        1           32 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
000007feef793510        1           32 System.Net.SafeLocalFree
000007feef78d980        1           40 System.Net.SafeCloseSocket
000007feef7a34e8        1           48 Microsoft.CSharp.CSharpCodeProvider
000007fef030fb18        2           64 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
000007fef030fa78        2           64 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
000007feef791048        1           80 System.Net.Sockets.NetworkStream
000007fef03101f8        3           96 Microsoft.Win32.SafeHandles.SafeFileHandle
000007feef78caa0        1          120 System.Net.Sockets.Socket
000007fef02fdd10        2          128 System.Threading.ReaderWriterLock
000007feef78f520        4          160 System.Net.SafeRegistryHandle
000007feef78cd08        5          160 System.Net.SafeCloseSocket+InnerSafeCloseSocket
000007feef78f368        4          192 System.Net.SafeCloseSocketAndEvent
000007fef03071f8        2          208 System.Threading.Thread
000007fef02ffc40        7          224 Microsoft.Win32.SafeHandles.SafeRegistryHandle
000007fef02f4978       10          320 Microsoft.Win32.SafeHandles.SafeWaitHandle
000007fef02fdc70       20          640 System.WeakReference
000007feef7a1de0       10         1680 System.Diagnostics.PerformanceCounter
Total 82 objects

添加我认为应该消失的随机对象的 !GCRoot 跟踪...

0:010> !GCRoot -nostacks 000000000288e110 
DOMAIN(000000000020B2B0):HANDLE(Pinned):e17b8:Root:0000000012840770(System.Object[])->
00000000028b5380(System.Collections.Hashtable)->
00000000028b53d8(System.Collections.Hashtable+bucket[])->
00000000028b5528(System.Collections.Hashtable)->
00000000028b5580(System.Collections.Hashtable+bucket[])->
00000000028c1f68(Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer)->
0000000002898a38(System.Xml.Serialization.XmlMembersMapping)->
0000000002898a70(System.Object[])->
0000000002898a98(System.Xml.Serialization.XmlMemberMapping)->
0000000002896950(System.Xml.Serialization.MemberMapping)->
00000000028b90a8(System.Object[])->
00000000028969b8(System.Xml.Serialization.ElementAccessor)->
0000000002896aa8(System.Xml.Serialization.StructMapping)->
0000000002895eb8(System.Xml.Serialization.StructMapping)->
00000000028928f8(System.Xml.Serialization.StructMapping)->
000000000288bd10(System.Xml.Serialization.StructMapping)->
0000000002890da8(System.Xml.Serialization.StructMapping)->
000000000288f8e8(System.Xml.Serialization.StructMapping)->
000000000288ea78(System.Xml.Serialization.StructMapping)->
000000000288dc70(System.Xml.Serialization.StructMapping)->
000000000288dd20(System.Xml.Serialization.NameTable)->
000000000288dd38(System.Collections.Hashtable)->
000000000288dd90(System.Collections.Hashtable+bucket[])->
000000000288e1f8(System.Xml.Serialization.AttributeAccessor)->
000000000288e2f0(System.Xml.Serialization.EnumMapping)->
000000000288e110(System.Xml.Serialization.TypeDesc)

【问题讨论】:

  • 顺便说一句,我知道我应该试试 { client.Close(); } 赶上 { 客户端.Abort(); }....我只是想在这里简明扼要地说明我的问题。
  • 我知道这是一篇旧帖子,但可能是客户端在 Main 方法范围内并且工作线程尚未展开(GC 认为客户端仍然有效)?将客户端代码放入方法中并在方法之后调用GC.Collect 怎么样?

标签: .net wcf memory windbg sos


【解决方案1】:

强制垃圾回收的必要性是什么?

如果您的 Channel 已关闭,CLR 会负责 GC。

Check this out>>>

【讨论】:

  • 我同意 - GC.Collect 不应该是必要的。我在这里这样做是为了确保 GC 在我进行堆转储之前运行,该堆转储仍然显示一堆 WCF 对象。
【解决方案2】:

XmlSerializer 体系结构静态缓存有关它遇到的类型的各种信息,因此它不必经常创建序列化程序(这完全有道理),所以这些东西没有被清理对我来说真的不足为奇向上。从您的 !GCRoot 转储中充斥着 System.Xml.Serialization 中的东西这一事实来看,这肯定是罪魁祸首。

【讨论】:

  • 同意。你也可以做一个 !SaveModule 并在反射器中打开它来检查类型。
  • 谢谢!这似乎是答案。 WCF 框架似乎在做类似的智能缓存。我认为这说明了我看到的 System.Net* 和相关对象。
【解决方案3】:

你检查过根吗?

【讨论】:

  • 感谢您的建议。我用随机 TypeDesc 元素上的 GCRoot 跟踪更新了我的问题(其中有很多闲逛)。
【解决方案4】:

我在 WinForms 中进行跟踪时发现,您必须执行两次 GC.Collect() 并在其间使用 Application.DoEvents() 才能强制收集足够好,以便使用内存跟踪器来查找泄漏。

我敢打赌 WPF 也是如此。

【讨论】:

  • 你真的是说 WPF 吗?...P 要求 WCF
  • 感谢您的建议!我试过了,但似乎不适用于这种情况:(
  • 我的意思是 WPF,但不知何故我认为这是核心运行时的产物,因此它也应该适用于 WCF。
  • 更新:GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();
【解决方案5】:

在客户端调用 dispose 之前,您将客户端设置为 null。

【讨论】:

  • 感谢您的建议。我的理解是 Close() 就足够了。 Dispose 甚至没有暴露在我的客户端上。根据您的建议,我将我的客户投射到 IDisposable 并调用 Dispose() 但这似乎并没有解决它(尝试了 Dispose(),然后是 Close(),反之亦然)。
猜你喜欢
  • 2013-05-19
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
相关资源
最近更新 更多