locked
Memory Leak ? RRS feed

  • Question

  • Bonjour,

    J'ai un doute sur la méthode WorkflowInvoker.Invoke, je pense qu'elle a un problème de fuite mémoire.

    Pour mettre en avant ce problème, créez un nouveau projet WF en mode console, et devant le WorkflowInvoker.Invoke (fichier program.cs), rajout ez while(true). Au bout de 15 secondes, on se retrouve avec un OutOfMemoryException...

    A savoir si l'exposition d'un workflow sur un webservice a les mêmes effets de fuite mémoire à chaque appel au endpoint...

    Si vous avez un avis sur la question, je suis preneur :)

    lundi 4 juillet 2011 08:11

Réponses

  • Sympa la vidéo ;)

    Mais vous n'avez pas voulu regardé la "la mémoire disponible" comme indiqué dans ma précédente réponse... Vous constaterez qu'elle diminue (très doucement, mais elle diminue).

    Si vous ne le constatez pas, je vous conseil de consulter la MSDN qui explique plutôt bien le phénomène.(je n'ai plus le lien, cette remarque est tellement ancienne :() je vous encourage donc à regarder aussi que le monitoring et le profilage d'application .net. Vous comprendrez ainsi mieux pourquoi je ne faisais pas référence à votre application mais à la "mémoire disponible" sur votre machine... avec .net les choses ne sont pas toujours ce que l'on croit.

    Certes la diminution de la mémoire disponible est ridicule, mais elle existe. Avec le WorkflowInvoker, vous avez tout un runtime de workflow qui se lance et à chaque appel vous en redemandez plus sans pour autant laisser la machine souffler. Le GC à beau tenté de faire son travail, il n'en a jamais l'occasion :(

    Dès que l'application est fermée, vous retrouvez votre mémoire car le GC fait son travail. On ne peut donc pas parler de "fuite".

    Dans votre vidéo, vous pouvez le constater par vous-même l’exception est lié à nouveau d’un type lié à la mémoire :(

    En temps normal, donc hors d’une boucle sans fin hyper volante, le GC pourra faire son travail et les ressources seront libérés (hors mis si vous n’utilisez pas IDisposable, là GC aura un peu plus de mal).

    Pour ce qui est des bonnes pratique WF à proprement parler :

    • Si vous devez lancer des sous workflow, utilisez le context de l’hôte et nom pas un second.
    • Si vous devez lancer une masse de workfows indépendants, il faut utiliser des sémaphores ou la TPL.
    • Si votre hôte est un workflowServiceHost, tout est déjà compris dans sa configuration de base.

    le WorkflowInvoker n'est pas prévu pour les usage cités ici ;)


    Jérémy Jeanson MVP, MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    lundi 4 juillet 2011 15:41
    Modérateur

Toutes les réponses

  • Bonjour Yohann,

    Personnellement j'ai testé avec une défintion Xaml et la même chose en version code :

    Activity w = new While
    {
      Condition = true
    };
    
    WorkflowInvoker.Invoke(w);
    

    J'ai laissé tourner une minute puis deux. Aucune execption remontée.

    J'utilise beaucoup les services et je n'ai rien constaté en ce qui concerne la mémoire (pour le moment).

     

    Peut on avoir confirmation qu'il s'agit bien d'un OutOfMemoryException dans votre cas?


    Jérémy Jeanson MVP, MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    lundi 4 juillet 2011 12:22
    Modérateur
  • Bonjour,

     

    Tout d'abord, merci pour votre réactivité :)

    Il s'agit bel et bien d'une exception de type OutOfMemoryException.

    Par contre, le cas de tests n'est pas tout à fait le même dans mon cas : Je créé simplement un nouveau projet workflow console vide, et à la place du classique WorkflowInvoker.Invoke(w), j'ai mis while(true) WorkflowInvoker.Invoke(w);

    Si je ne trompe pas, dans votre cas, la boucle est dans le workflow et il n'y a qu'une seule invocation. Dans mon cas, la boucle est à l'extérieur du workflow, et j'ai une infinité d'appels à la méthode invoke.

    En fait, ce qui me gène le plus, c'est que j'ai adapté du code existant pour faire du workflow foundation, et que j'ai des CodeActivity qui font des WorkflowInvoker.invoke. Dans ces cas aussi, la mémoire monte (plus lentement, mais elle monte). Le seul moyen que j'ai pour ne pas exploser la mémoire, c'est de ne jamais faire de WorkflowInvoker.Invoke dans mes CodeActivity, car sinon, je peux facilement avoir un memory overflow...

    Si vous le souhaitez, je peux vous envoyer un projet Visual Studio pour que vous puissiez constater le problème.

     

    Cordialement,

     

    Yoann

    lundi 4 juillet 2011 12:31
  • Bonjour Yoann,

    Pardon, j'ai effectivemnt raté le fait que ce soit l'onvocation qui soit dans le while :(

    Makhaeureusement, votre test n'est pas pertinant... Avez vous tenté d'utiliser le code suivant :

    while (true)
    {
    }
    

    Il n'y a pas de WorkflowInvoker, et pourtant, votre mémoire disponible va diminuer et vous allez effectivement avoir un OutOfMemoryException. Ceci est une protection de la CLR contre ce genre de code "malveillant".

    WF4 n'est donc pas en cause ;)

     

    Note : Pour ce qui est de votre "CodeActivity", je vous conseil d'ouvir un second poste pour parler de votre activité, car les activités personnlisés sont vraiment d'un autre sujet que le WorkflowInvoker.


    Jérémy Jeanson MVP, MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    lundi 4 juillet 2011 12:52
    Modérateur
  • J'ai fait le test que vous décrivez :

    namespace WorkflowConsoleApplication1
    {
     
        class Program
        {
            static void Main(string[] args)
            {
                while (true) { }
            }
        }
    }

     

    La mémoire ne monte pas, et je n'ai pas de OutOfMemoryException...

    Pour ce qui est des CodeActivity, j'en parlais car si elles font elles-même des WorkflowInvoker.Invoke, elles font elles aussi monter la mémoire sans que celle-ci soit libérée...

    lundi 4 juillet 2011 13:25
  • Oh que si, la mémoire monte!!!

    Ouvrez votre gestionnaire de tâches windows et regarder bien la mémoire disponible, elle diminuera progressivement.

    Si vous rester quelques minutes, l’exception finira par ce lever. C’est un mécanisme bien connu.

     

    Pour ce qui est d'utiliser le workflowinvoker dans un workflow, je vous proposais d'en parler dans une autre conversation, car il s'agit de dissocier l'hôte des définitions. Dans votre cas, l'utilisation d'un hôte dans une instance s'opose aux bonnes pratique qui veulent que l'on utilise le context pour demander à l'hôte courant d'invoquer le sous workflow au lieu d'instancier un second hôte.


    Jérémy Jeanson MVP, MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    lundi 4 juillet 2011 13:35
    Modérateur
  • Je vous ai fait une vidéo qui prouve l'inverse.

    http://www.youtube.com/watch?v=xD0mRWJazis

     

    lundi 4 juillet 2011 14:56
  • Sympa la vidéo ;)

    Mais vous n'avez pas voulu regardé la "la mémoire disponible" comme indiqué dans ma précédente réponse... Vous constaterez qu'elle diminue (très doucement, mais elle diminue).

    Si vous ne le constatez pas, je vous conseil de consulter la MSDN qui explique plutôt bien le phénomène.(je n'ai plus le lien, cette remarque est tellement ancienne :() je vous encourage donc à regarder aussi que le monitoring et le profilage d'application .net. Vous comprendrez ainsi mieux pourquoi je ne faisais pas référence à votre application mais à la "mémoire disponible" sur votre machine... avec .net les choses ne sont pas toujours ce que l'on croit.

    Certes la diminution de la mémoire disponible est ridicule, mais elle existe. Avec le WorkflowInvoker, vous avez tout un runtime de workflow qui se lance et à chaque appel vous en redemandez plus sans pour autant laisser la machine souffler. Le GC à beau tenté de faire son travail, il n'en a jamais l'occasion :(

    Dès que l'application est fermée, vous retrouvez votre mémoire car le GC fait son travail. On ne peut donc pas parler de "fuite".

    Dans votre vidéo, vous pouvez le constater par vous-même l’exception est lié à nouveau d’un type lié à la mémoire :(

    En temps normal, donc hors d’une boucle sans fin hyper volante, le GC pourra faire son travail et les ressources seront libérés (hors mis si vous n’utilisez pas IDisposable, là GC aura un peu plus de mal).

    Pour ce qui est des bonnes pratique WF à proprement parler :

    • Si vous devez lancer des sous workflow, utilisez le context de l’hôte et nom pas un second.
    • Si vous devez lancer une masse de workfows indépendants, il faut utiliser des sémaphores ou la TPL.
    • Si votre hôte est un workflowServiceHost, tout est déjà compris dans sa configuration de base.

    le WorkflowInvoker n'est pas prévu pour les usage cités ici ;)


    Jérémy Jeanson MVP, MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    lundi 4 juillet 2011 15:41
    Modérateur
  • Bonjour Yoann,

    La liste de bonnes pratiques présentée via mon précédent message vous a-t-elle permis de régler vos soucis de performances?


    Jérémy Jeanson MVP, MCP, MCTS http://blogs.codes-sources.com/JeremyJeanson/ (French or English spoken)
    jeudi 4 août 2011 12:51
    Modérateur