IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API, COM et SDKs Delphi Discussion :

TServerEventDispatch et fuite mémoire


Sujet :

API, COM et SDKs Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut TServerEventDispatch et fuite mémoire
    Bonjour à tous,

    Mon projet utilise une bibliothèque de type importé (fichier TLB) me permettant d'appeler des méthodes distantes sur un serveur COM mais également de recevoir des événements entrants depuis ce serveur COM.

    Seulement voilà, le fait d'utiliser des composants générés de cette bibliothèque de type (des classes héritant de TOleServer) m'entraînent systématiquement des fuites mémoire.

    En effet un rapport mémoire de FastMM m'indique la chose suivante :
    4048E6 [System.pas][System][@GetMem][3693]
    40556F [System.pas][System][TObject.NewInstance][11044]
    405B02 [System.pas][System][@ClassCreate][12121]
    59F104 [OleServer.pas][OleServer][TServerEventDispatch.Create][117]
    20036
    59F3DE [OleServer.pas][OleServer][TOleServer.Create][253]
    59FDD0 [U_OleTools.pas][U_OLETools][TDiaOleServer.Create][254]
    5CE158 [DiaServeur_TLB.pas][DiaServeur_TLB][TDiaConnexion.Create][35256]
    658F6C [U_DiaCore.pas][U_DiaCore][TDiaCore.Create][1928]
    6F264E
    406B58 [System.pas][System][InitUnits][15458]
    406BC4 [System.pas][System][@StartExe][15523]
    40B9B7 [SysInit.pas][SysInit][@InitExe][770]
    6F3410
    755033CA [BaseThreadInitThunk]
    77689ED2 [Unknown function at RtlInitializeExceptionChain]
    77689EA5 [Unknown function at RtlInitializeExceptionChain]
    Le bloc était actuellement utilisé pour un objet de la classe: TServerEventDispatch


    En vérité le simple fait d'utiliser une instance "TOleServer" utilisant en interne une instance de "TServerEventDispatch " entraîne une fuite mémoire. J'ai essayé depuis pas mal de temps de savoir d'où cela provenait, mais tout ce que j'ai pu voir c'est que j'ai des appels à "TServerEventDispatch.QueryInterface(const IID: TGUID; out Obj)" (en provenance de la dll "ole32.dll" ou "auto32.dll" je crois), qui entraine un appel un 'TObject.GetInterface(const IID: TGUID; out Obj)' entrainant un incrément sur le nombre de référence qui n'est pas suivi décrémentation du nombre de référence correspondant. Comme si l'objet "Obj" retourné n'était pas libéré. Le problème c'est que cette récupération de l'objet semble être provoqué par une dll Windows et que je n'ai donc à priori pas de moyen de contrôler/corriger cela.
    Je pense qu'il doit y avoir un problème dans mon code, ou à la limite avec la VCL, enfin quelque chose que je pourrais corriger...

    Quelqu'un aurait-il des idées sur la manière de corriger cela ? Merci par avance.

    Je suis surpris de ne rien trouver sur Internet concernant ce problème et c'est pourquoi je créé ce topic.

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 096
    Par défaut
    tu as bien un Destructor qui met la référence à nil ou un free des objets dans le code auto-généré !

    Moi, même dans mon code, je veille à bien mettre à nil mes interfaces créées par des CoClasses issues de TLB !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    tu as bien un Destructor qui met la référence à nil ou un free des objets dans le code auto-généré !

    Moi, même dans mon code, je veille à bien mettre à nil mes interfaces créées par des CoClasses issues de TLB !
    Bien sûr le code auto-généré créé des objets héritant de "TOleServer" (dans mon cas des "TDiaOleServer" mais cela ne change rien je n'ai pas surchargé les constructeurs/destructeurs).

    Le code de construction/destruction est le suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    {TOleServer}
    constructor TOleServer.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      // Allow derived class to initialize ServerData structure pointer
      InitServerData;
      // Make sure derived class set ServerData pointer to some valid structure
      Assert(FServerData <> nil);
      // Increment instance count (not used currently)
      Inc(FServerData^.InstanceCount);
      // Create Event Dispatch Handler
      FEventDispatch := TServerEventDispatch.Create(Self);
    end;
     
    destructor TOleServer.Destroy;
    begin
      // Disconnect from the Server (NOTE: Disconnect must handle case when we're no longer connected)
      Disconnect;
      // Free Events dispatcher
      FEventDispatch.ServerDisconnect;
      if (FEventDispatch._Release = 0) then FEventDispatch.Free;
      // Decrement refcount
      Dec(FServerData^.InstanceCount);
      inherited Destroy;
    end;

    Le problème est que lors de l'appel à "Destroy" FEventDispatch._Release ne retourne jamais 0 mais plutôt 3 ou 4... à cause de ces incréments de références qui ne seront jamais été décrémentés en retour (même après la destruction du TOleServer). Effectivement 'FEventDispatch' est récupéré via l'interface. Mais non par mon code à priori puisque je me contente de poser mon composant qui est une instance de "TDiaOleServer" sur ma fiche et je l'utilise pour appeler des méthodes et recevoir des événements : donc je ne gère aucune création/libération.
    Le simple fait de poser un composant héritant de "TOleServer" (donc d'utiliser un composant généré par l'import d'une bibliothèque de type) pouvant générer des événements semble entrainer une fuite mémoire car pas de libération des instances de "TServerEventDispatch"...



    [Edit]

    J'ai noté un problème similaire avec les instances "TDispatchSilencer" côté serveur COM (car c'est également nous qui l'avons codé en Delphi, et nous l'utilisons à travers une bibliothèque de type dans nos différents modules). En effectuant des recherches sur Internet je suis tombé sur un topic à toi, qui parle de "dézinguer" TDispatchSilencer. Et en réalité j'ai fait exactement comme toi en réimplémentant "EventConnect" dans ma classe "TDiaAutoObject" qui hérite de "TAutoObject" (tout comme "TDiaOleServer" hérite de "TOleServer").

    Pourquoi voulais-tu dézinguer "TDispatchSilencer" ? Car personnellement à part me causer une fuite mémoire je n'en vois pas l'intérêt mais je ne suis pas sûr de ma modification. Voici le lien pour rappel (car cela remonte à pas mal d'années ;-) ) :

    http://www.developpez.net/forums/d98...cer-eventsink/

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Chose assez surprenante : le fait d'avoir dézinguer "TDispatchSilencer" côté "Serveur COM" m'a fait également disparaitre les fuites mémoires côté client... donc effectivement les "AddRef" étaient bien provoqués de "l'extérieur"... à savoir... reste maintenant à savoir comment récupérer les informations d'une exception ayant lieu lors d'un appel sortant n'utilisant pas la convention "safecall"... (comme tous les appels réalisés via "IDispatch.Invoke")...

  5. #5
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 096
    Par défaut
    un safecall, c'est un stdcall avec HRESULT !
    C'est assez drôle que mon sujet "Quelle est la méthode propre pour éviter le TDispatchSilencer dans un EventSink " resté sans réponse à l'époque t'es résolu tes fuites mémoires

    Je sais que si l'on utilise le Wrapper TLB, cela génère le code pour la gestion d'évènement automatiquement mais l'on perd aussi du coup le contrôle (modifié une TLB est évidemment périlleux puisque c'est un fichier généré)

    J'ai suivi le Tutoriel de Laurent Dardenne pour gérer les Events, et IDispatch.Invoke renvoie un code d'erreur, c'est lui que je gérais dans mon serveur en réponse des gestionnaires d'évènements qui pouvait échouer !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    un safecall, c'est un stdcall avec HRESULT !
    C'est assez drôle que mon sujet "Quelle est la méthode propre pour éviter le TDispatchSilencer dans un EventSink " resté sans réponse à l'époque t'es résolu tes fuites mémoires

    Je sais que si l'on utilise le Wrapper TLB, cela génère le code pour la gestion d'évènement automatiquement mais l'on perd aussi du coup le contrôle (modifié une TLB est évidemment périlleux puisque c'est un fichier généré)

    J'ai suivi le Tutoriel de Laurent Dardenne pour gérer les Events, et IDispatch.Invoke renvoie un code d'erreur, c'est lui que je gérais dans mon serveur en réponse des gestionnaires d'évènements qui pouvait échouer !

    Ok mais cela dit je ne saisis pas pourquoi tu voulais te débarraser de "TDispatchSilencer" (moi c'était à cause des fuites mémoire et qu'en regardant le code, je ne comprenais pas son intérêt mais toi ?).

    Sinon entre temps j'ai trouvé comment retourner une exception avec la convention d'appel "stdcall", il faut refaire ce que fait en interne la convention d'appel "safecall". A savoir retourner un HRESULT = DISP_E_EXCEPTION et remplir la structure pointée par "ExcepInfo" (fait partie des arguments de "Invoke"). Je me suis inspiré de ce qui se fait déjà dans la VCL ("OleComAuto.TObjectDispatch.Invoke").

    Je n'ai donc plus de fuites mémoire, et en plus je peux désormais gérer convenablement mes exceptions. Cool ^^ !

    Note : Concernant le fichier TLB généré par Delphi, j'ai créé un outil interne qui le parse afin d'effectuer des modifications dans le code (ne pas utiliser de Variant inutilement + utilisation de "TDiaOleServer" plutôt que "TOleServer", etc...). Donc effectivement je n'ai pas eu à me palucher à la main tout de code de gestion d'interface sortante, mais j'ai pu l'adapter quand même en écrivant des classes héritées et en utilisant mon outil.

    Par contre sous Delphi XE je crois qu'on ne peut plus importer de bibliothèques de type, il doit y avoir une autre fonctionnalité équivalente. Reste à la trouver...

Discussions similaires

  1. [tomcat][memoire] java.net.URL et fuite mémoire
    Par Seiya dans le forum Tomcat et TomEE
    Réponses: 6
    Dernier message: 09/03/2009, 10h41
  2. [Fuites mémoire] Je cherche un utilitaire
    Par 10_GOTO_10 dans le forum C++Builder
    Réponses: 8
    Dernier message: 10/02/2005, 10h03
  3. Outil de recherche de fuite mémoire
    Par eag35 dans le forum MFC
    Réponses: 4
    Dernier message: 02/02/2005, 12h46
  4. [SWT]SWT et fuite mémoire(ou pas)
    Par menuge dans le forum SWT/JFace
    Réponses: 2
    Dernier message: 22/06/2004, 21h40
  5. [debug] fuites mémoires
    Par tmonjalo dans le forum C
    Réponses: 3
    Dernier message: 28/07/2003, 17h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo