Pergunta

Aqui está meu cenário:

  1. Inicie o meu programa de teste e quebrar imediatamente para o depurador (WinDBG)
  2. Faça um! Dumpheap -stat e observar que não há System.Net * ou System.Xml * objetos em qualquer lugar
  3. Criar o meu cliente WCF, fazer um pedido WCF
  4. Fechar o cliente WCF e força GC.
  5. Tome um! Dumpheap -stat e observador há toneladas de System.Net *, System.Xml * ainda objetos na memória.

Assim, a partir minha observação na etapa # 5, parece que WCF não é limpar adequadamente (ou mais provável que eu estou faltando alguma coisa). Por que é isso? Como posso recuperar a memória ocupada por estes objetos que não deveria estar aqui?

Aqui está o meu código de teste ...

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();
    }
}

P.S. Aqui estão meus resultados! FinalizeQueue ... não tenho certeza se isso é relevante

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

Adicionando traço! Gcroot de um objeto aleatório que eu acho que deve ser ido ...

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)
Foi útil?

Solução

A arquitetura XmlSerializer estaticamente armazena todos os tipos de informações sobre os tipos que tem encontrado para que ele não sempre tem que criar serializers (que totalmente faz sentido), por isso é realmente nenhuma surpresa para mim que essas coisas não estão sendo limpos acima. A julgar pelo fato de que o despejo! Gcroot está repleta de coisas a partir do System.Xml.Serialization, com certeza parece ser o culpado.

Outras dicas

O que é a necessidade de forçar uma coleta de lixo?

Se o seu canal está fechado o CLR cuida de GC.

Marque esta fora >>>

Será que você verifique as raízes?

Eu descobri quando o rastreamento em WinForms que você tinha que fazer um GC.Collect () duas vezes com um Application.DoEvents () entre a recolha de força bem o suficiente para usar um marcador de memória para olhar se há vazamentos.

Eu aposto que o mesmo é verdade para WPF.

Você está definindo o cliente nulo, antes de Dispose é chamado no cliente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top