J'ai une application client WCF qui fait un seul appel de service avec une réponse très importante (1GB). Je constate que cet appel de service utilise beaucoup de mémoire (500 Mo) qui semble ne jamais être récupérée, même si les objets de la réponse ne sont plus référencés par mon code.
J'ai utilisé un profileur de mémoire pour voir qu'une grande partie de l'utilisation de la mémoire se trouve dans les tableaux d'octets créés par les instances de PooledBufferManager.
Le proxy/client que j'utilise a été généré automatiquement par Visual Studio, il s'agit donc d'une classe dérivée de System.ServiceModel.ClientBase< TChannel >.
J'utilise une liaison personnalisée avec la configuration suivante :
<customBinding>
<binding name="foo"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:01:00"
sendTimeout="00:01:00">
<transactionFlow/>
<reliableSession ordered="true" inactivityTimeout="00:02:00"/>
<security authenticationMode="SecureConversation" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<secureConversationBootstrap messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings maxClockSkew="23:59:00"/>
</secureConversationBootstrap>
<localClientSettings maxClockSkew="23:59:00"/>
</security>
<mtomMessageEncoding>
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</mtomMessageEncoding>
<httpTransport maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>
</binding>
</customBinding>
En lisant autour de moi, les gens parlent de quelques solutions à ce problème :
- le passage au mode de réponse en continu plutôt qu'en mémoire tampon, mais je crois que c'est pour les connexions TCP WCF, et non pour HTTP comme la mienne.
- la définition de maxBufferPoolSize à zéro pour désactiver les pools de tampons. Ce réglage dans l'élément httpTransport ne semble pas avoir d'effet pour moi.
- en appelant Clear() sur le BufferManager/PooledBufferManager approprié. Je n'arrive pas à trouver l'objet sur lequel appeler cela dans le contexte de l'instance dérivée ClientBase que j'ai. J'ai réussi à trouver l'instance PooledBufferManager appropriée en utilisant le débogueur et en creusant à plusieurs niveaux dans les champs privés innerChannelFactory, mais cela n'est pas utile pour interagir avec elle à partir du code.
- l'invocation manuelle de GC.Collect() semble récupérer environ 50 Mo sur les 500 Mo restants.
Quel serait le meilleur moyen de récupérer le maximum de la mémoire utilisée par cet appel de service unique ? Je suis sur le point de faire l'appel de service dans un processus dédié que je peux tuer pour récupérer la mémoire à ce stade.