7
votes

Comment utiliser Idisposable pour réparer des fuites de mémoire

J'ai une application .NET qui semble avoir une ou des problèmes de fuite de mémoire. Le service .NET commence environ 100 Mo de mémoire, mais sous charge, il frappe environ 400-500 Mo. La plupart de mes classes n'ont pas de ressources non gérées, et celles qui mettent déjà la mise en œuvre isisposable. Donc, ma question est de gifler Idisposable sur mes classes aident?

Le 4-500 MB n'est pas lui-même concernant. La préoccupation est qu'il existe 8 services différents. Chacun est construit à l'aide de Sharparch, Nservicebus, Windsor et Nibernate. Mon sentiment est qu'il y a quelque chose dans l'un d'entre eux qui causent un problème. Mon inquiétude est que la mémoire totale de tous les services est d'environ 3,2 à 3,6 gigs de mémoire sur 4 conclusions. Il ne jette pas encore des exceptions exceptionnelles Aussi, j'ai utilisé DotTrace, qui me donne des informations, je ne sais tout simplement pas comment agir sur cette information


0 commentaires

5 Réponses :


4
votes

Réponse courte: Non.

Réponse plus longue: NOOOOOOO.

Je pense que vous saviez déjà cela - si vous ne l'avez pas fait, vous n'auriez pas "giflé" isisposable sur les classes qui en ont besoin - Idisposable n'a rien à voir avec le GC. La seule chose qui compte vraiment ici, c'est si vous avez des derniers finaliseurs (~ classname) sur vos objets inucidément - cela leur permettra de sauvegarder dans la file d'attente finaliseur à une seule-filetage avant de recevoir GC'D, peu importe d'entre elles contenant des ressources non gulmanes. ou pas.


0 commentaires

15
votes

Si toutes les classes qui ont des ressources non gérées implémentent Idisposable et sont correctement éliminées (via ou essayez / finalement), ajoutent d'autres Idisposable implémentations n'importe quoi.

Le premier problème est que vous ne savez pas pourquoi vous fuiez. Les applications gérées se fuient généralement pour l'une des raisons suivantes

  1. ne disposant pas correctement de ressources non gérées
  2. Tenir sur de gros graphiques d'objets d'objets gérés

    Compte tenu des informations de votre question, il est presque certainement n ° 2 qui cause le problème. Vous aurez besoin d'obtenir un profileur ou un windbg pour vous dire quelle est la fuite réelle et quels objets enracinés le causent.

    Voici un excellent article de Rico pour vous aider à démarrer


0 commentaires

5
votes

La réponse est, presque certainement pas. Avez-vous vérifié que vous vous tenez réellement sur la mémoire que vous ne devriez pas être, en profilant de votre service?

Gardez à l'esprit que le collecteur des ordures peut ne pas relâcher la mémoire jusqu'à ce qu'il ne soit nécessaire, il n'est donc pas inhabituel que cela ne soit pas inhabituel qu'il ait atteint 400-500 Mo alloué. Le point à laquelle je serais inquiété serait quand, après une [insérer une période de temps raisonnable ici] d'utilisation, il est en train de se glisser plus loin et a atteint 1 Go, même s'il n'a pas été sous un niveau de charge plus élevé.


0 commentaires

17
votes

Ma première préoccupation serait de veiller à ce que vous mesuriez quelque chose de pertinent. "Mémoire" peut signifier beaucoup de choses différentes. Il y a une différence énorme entre l'épuisement de l'espace de mémoire virtuelle et l'essor de la RAM. Il y a une différence énorme entre un problème de performance provoquée par la rotation du fichier de page et un problème de performance causé par la création de trop de pression de GC.

Si vous ne comprenez pas ce que les relations sont entre la RAM, la mémoire virtuelle, le jeu de travail et le fichier de page, alors commencez à lire jusqu'à ce que vous comprenez tout ce genre de choses. La façon dont vous avez formulé la question me conduit à soupçonner que vous croyez que la mémoire virtuelle et la RAM sont la même chose. ils ne sont certainement pas.

Je soupçonne que l'arithmétique que vous faites est:

  • J'ai huit processus qui consomment chacun 500 millions d'octets d'espace d'adresses virtuel
  • J'ai quatre milliards d'octets de RAM
  • Par conséquent, je suis sur le point d'obtenir une exception exceptionnelle

    Ce syllogisme est complètement invalide. C'est le syllogisme:

    • J'ai huit litres de glace
    • J'ai de la place pour neuf litres de crème glacée dans le congélateur
    • Par conséquent, si je reçois deux plus de trembles de crème glacée, quelque chose va fondre

      En fait, vous avez une installation de stockage froide de taille d'entrepôt entière à côté. Rappelez-vous que RAM est juste un moyen rapide de stocker des trucs près de l'endroit où vous en avez besoin, comme votre réfrigérateur. Si vous avez plus de choses qui doivent être stockées, qui se soucie si vous manquez de pièce localement? Vous pouvez toujours faire sauter la porte à côté et mettre les choses que vous utilisez moins fréquemment dans un gel profond à long terme - le fichier de page. C'est moins pratique , mais rien fond .

      Vous obtenez une exception "hors mémoire" lorsqu'un processus est sorti de l'espace d'adressage virtuel, pas lorsque toute la RAM du système est consommée. Lorsque toute la RAM dans le système est consommée, vous n'obtenez pas d'erreur, vous obtenez performances de la merde car le système d'exploitation consacre tout son temps à exécuter des objets de disque.

      Donc, de toute façon, commencez par comprendre ce que vous mesurez et comment fonctionne la mémoire de Windows. Ce que vous devriez réellement rechercher est:

      • est un processus en danger d'utiliser plus de deux milliards d'octets de mémoire virtuelle sur un système 32 bits? Un processus ne fait que 2 Go de mémoire virtuelle (pas la RAM, N'oubliez pas que la mémoire virtuelle n'a rien à voir avec la RAM: C'est pourquoi son appelé "virtuel" - ce n'est pas matériel ) sur Win32 qui est adulsible par code d'utilisateur; Vous obtiendrez une oom si vous essayez d'en utiliser plus.

      • est un processus en danger d'essayer d'allouer un vaste bloc de mémoire virtuelle de sorte qu'il n'y ait pas de bloc contigu de cette taille libre? Êtes-vous susceptible d'allouer dix millions d'octets de données dans un seul tableau, par exemple? Encore une fois, OOM.

      • est l'ensemble de travail - c'est-à-dire les pages de mémoire virtuelle d'un processus * requis pour être en RAM pour des raisons de performance - de tous les processus inférieurs à la quantité de RAM disponible? Sinon, alors bientôt, vous obtiendrez battre, mais pas un OOM.

      • est votre fichier de page suffisamment grand pour gérer les pages de mémoire virtuelles pouvant être spécialisées sur le disque si la RAM commence à être courte?

        Jusqu'à présent, rien de tout cela n'a rien à voir avec .NET. Une fois que vous avez réellement déterminé qu'il y ait un problème réel , il pourrait ne pas y avoir - alors commencez à enquêter en fonction de ce que le problème réel est. Utilisez un profileur de mémoire pour examiner ce que font l'allocateur de la mémoire et le collecteur des ordures. Voyez s'il y a des blocs énormes dans le grand tas d'objets ou de gros graphiques d'objets vivants qui ne peuvent pas être collectés, ni quoi. Mais utilisez de bons principes d'ingénierie: Comprenez le système, utilisez des outils pour rechercher les performances empiriques réelles, expérimenter des modifications et mesurer soigneusement leurs résultats. Ne commencez pas simplement à gifler de manière aléatoire des interfaces idissibles magiques sur quelques classes et espérons que cela fait le problème - s'il y en a un - parti.


0 commentaires

2
votes

mesure, mesure, mesure

Si vous souhaitez réduire l'utilisation de la mémoire pour votre application, vous devez d'abord déterminer où il est utilisé.

Vous pouvez avoir une idée approximative en ajoutant quelques compteurs de Perfmon sur "octets privés, octets de tous les tas, octets dans le grand tas, Gen 1, Gen 2" et ainsi de suite.

Si vous déterminez que vous utilisez trop de mémoire gérée. Vous pouvez décomposer l'utilisation encore plus avant d'utiliser un outil tel que profileur de mémoire .NET ou le très flexible mais WINDBG + SOS

Une fois que vous avez isolé où votre mémoire vous permet de rechercher des stratégies pour réduire l'utilisation, cela pourrait être aussi simple que de remplacer un dictionnaire avec un cache ou d'ajouter un constructeur de cordes.

La solution très peu susceptible de saupoudrer sur tout.


2 commentaires

Je dirais que avant votre première étape, il est utile de décider si vous avez vraiment un problème.


@John est totalement d'accord avec vous sur ce