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

Langage Delphi Discussion :

Forcer la destruction d'un objet


Sujet :

Langage Delphi

  1. #1
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut Forcer la destruction d'un objet
    Bonjour,

    Je constate dans mon application que la commande "free" ne libère pas forcément la mémoire associée à un objet.
    voici un exemple de code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    var monObjet:TSQLStoredProc;
    begin
       monObjet:=TSQLStroredProc.create(nil);
      with monObjet do
      begin
            SQLConnection:=maConnexion;       
            storedprocname:=maprocedure;
           open;
           //ici traitement des données lues
      end;
    monObjet.close;
    monObjet.free;
    end;
    Après l'appel "monObjet.free", la variable ne passe pas à nil. Sa propriété componentState passe à csDestroying mais l'objet reste en mémoire, comme s'il attendait un garbageCollector.
    Résultat, lorsque la procédure est appelée en boucle, la mémoire sature et je finis par avoir l'erreur "mémoire insuffisante"
    Existe-t-il un moyen de forcer la destruction de cet objet?

  2. #2
    Membre expérimenté
    Avatar de retwas
    Homme Profil pro
    Développeur Java/Delphi
    Inscrit en
    Mars 2010
    Messages
    698
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur Java/Delphi
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 698
    Points : 1 608
    Points
    1 608
    Billets dans le blog
    4
    Par défaut
    FreeAndNil ?

  3. #3
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    Déjà essayé, pas mieux

  4. #4
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 561
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 561
    Points : 3 955
    Points
    3 955
    Par défaut
    As-tu consulté les sources de ta classe ?

    Tu compiles bien en 32 bits ?

  5. #5
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    Citation Envoyé par e-ric Voir le message
    As-tu consulté les sources de ta classe ?

    Tu compiles bien en 32 bits ?
    Oui, c'est moi qui les écris les classes
    En général, je n'ai pas de problème, mais là, la classe en question c'est TSQLStoredProc (foruni par DBX)

    J'ai fait un test rapide en remplaçant le TSQLStoredProc par un TSQLQuery, l'empreinte mémoire augmente moins vite

  6. #6
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 561
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 561
    Points : 3 955
    Points
    3 955
    Par défaut
    (je parle dans le cadre de Delphi 7)

    Es-tu sûr d'atteindre le Free pour commencer ? est-ce que l'ajout d'un bloc protégé n'améliorerait pas la situation ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    monObjet:=TSQLStroredProc.create(nil);
    try
      with monObjet do
      begin
        SQLConnection:=maConnexion;       
        storedprocname:=maprocedure;
        open;
        //ici traitement des données lues
      end;
      monObjet.close;
    finally
      monObjet.free;
    end;
    Pour approfondir, active les DCU de débogage et trace l'exécution dans les sources de la VCL (je sais, c'est fastidieux). L'unité est SqlExpr pour les composants DBExpress.

    Autre piste: tu parles de boucle dans ton premier post, peux-tu déplacer la boucle dans la partie traitement des données lues ? de manière à n'ouvrir qu'une seule fois la procédure stockée.

    @+

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 : 13 586
    Points : 25 262
    Points
    25 262
    Par défaut
    On peut alléger la syntaxe à l'extrême

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      with TSQLStroredProc.create(nil) do
      try
        SQLConnection:=maConnexion;       
        storedprocname:=maprocedure;
        open;
        //ici traitement des données lues
        close;
      finally
        free;
      end;
    Pour le phénomène GarbageCollector, je t'invite a fouillé sur le forum au sujet du gestionnaire de mémoire de Delphi 2007 basé sur FastMM
    Et sa gestion de la mémoire via allocation de bloc

    Est-ce que tu ne lance QUE le code que tu as fourni pour ton test mémoire ?
    Si oui, effectivement, le TSQLStroredProc serait en cause
    Si non, ton traite fausse le test de fuite évidemment

    Ce n'est peut-être pas ton TSQLStroredProc qui fuit mais un autre objet alloué dans le même bloc
    Comme tu appelles surement tout le temps le code par le même chemin, tu as toujours cet autre objet
    À un final, comme tu as un autre qui fuit, c'est tout le bloc qui est bloqué

    Sinon, il n'y a pas forcément de mise à zéro du contenu dans objet, les pointeurs sont mis à nil via FreeAndNil même si je le fais, Est-ce bien utile ? par exemple un double appel de destroy fait mal en fin d'application (si un invalid pointer ... n'arrive pas avant)
    ne pas oublier que le Destroy utilisé pour nettoyer une exception dans le Create

    Parfois l'erreur "mémoire insuffisante" est fausse, c'est plutôt un problème de handle disponible ou qu'il n'arrive pas à allouer dans un bloc la mémoire demandée, j'ignore comment fonctionne une variable allouée dans plusieurs bloc (Est-ce possible ?)

    Par contre, les entiers comme componentState reste en mémoire, en fait, si tu conserve le pointeur, la zone de mémoire tant qu'elle n'est pas réutilise contient les valeurs de l'objet
    C'est un autre traitement qui aura peut-être un emplacement qui chevauche celui laissé libre par TSQLStoredProc qui modifiera le contenu, un autre objet commencera par tout mettre à zéro, un record déclaré en variable locale lui contiendra les valeurs et faudra pas oublier de bien remplir ce record !

    En C++Builder 2007 et XE2, j'ai utilise massivement du TSQLQuery, instancié et libéré à la volée dans des programmes batch tournant 24/24 pendant plusieurs mois sans être éteind, je n'ai pas vu de fuite mémoire dans ces composants, le volume de donnée était très faible, un Open ne renvoyait souvent qu'une ligne précise
    les requetes renvoyant genre 1000 ou 10000 était lancé au démarrage de programme ou lors d'une opération de synchronisation (10 à 100 fois par jour, rien par rapport au 10 000 à 100 000 event jour inséré dans l'historique)

    le ficher DB de Sybase Anywhere ne faisait que 5Mo pour la DB de config et par fois entre 100Mo et 1Go sur l'historique des 3 derniers mois mais ce dernier n'était que alimenté par les batch, sa consultation n'étant que dans les modules de stat et reporting qui eux consommait allégrement (pire sous Crystal 12 en .NET)
    je n'utilisais pas le TSQLStoredProc

  8. #8
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Est-ce que tu ne lance QUE le code que tu as fourni pour ton test mémoire ?
    Si oui, effectivement, le TSQLStroredProc serait en cause
    Si non, ton traite fausse le test de fuite évidemment
    Ce n'est peut-être pas ton TSQLStroredProc qui fuit mais un autre objet alloué dans le même bloc
    Comme tu appelles surement tout le temps le code par le même chemin, tu as toujours cet autre objet
    À un final, comme tu as un autre qui fuit, c'est tout le bloc qui est bloqué
    En réalité, j'exécute du code avant et après, mais lorsque je place ce bloc en commentaires, il n'y a plus de fuite.
    Pour répondre à e-ric, oui je suis sûr d'atteindre le free, j'y ai placé un point d'arrêt pour contrôler.

    Citation Envoyé par ShaiLeTroll Voir le message
    Parfois l'erreur "mémoire insuffisante" est fausse, c'est plutôt un problème de handle disponible ou qu'il n'arrive pas à allouer dans un bloc la mémoire demandée, j'ignore comment fonctionne une variable allouée dans plusieurs bloc (Est-ce possible ?)
    Effectivement, ce message d'erreur apparait ne exécution "standard". En mode debug, l'erreur exacte est "DBX: Erreur fournisseur". Mais je n'ai trouvé aucune aide ou piste avec cette erreur et comme je vois augmenter l'empreinte mémoire au fur et à mesure de l'exécution, je me suis concentré sur la fuite de mémoire.

    Citation Envoyé par ShaiLeTroll Voir le message
    Par contre, les entiers comme componentState reste en mémoire, en fait, si tu conserve le pointeur, la zone de mémoire tant qu'elle n'est pas réutilise contient les valeurs de l'objet
    C'est bon à savoir

    Citation Envoyé par ShaiLeTroll Voir le message
    C'est un autre traitement qui aura peut-être un emplacement qui chevauche celui laissé libre par TSQLStoredProc qui modifiera le contenu, un autre objet commencera par tout mettre à zéro, un record déclaré en variable locale lui contiendra les valeurs et faudra pas oublier de bien remplir ce record !
    C'est justement parce que j'avais envisagé cette hypothèse que je cherche un moyen de "vider" la mémoire occupée par le TSQLProc après son exécution.

    Citation Envoyé par ShaiLeTroll Voir le message
    je n'utilisais pas le TSQLStoredProc
    Moi non plus. Dans ce cas précis, c'est pour faciliter le portage sur d'autres SGBDR, mais effectivement, j'observe une nette amélioration en remplaçant le TSQLStoredProc par un tQuery.
    Je crois que je devrais m'orienter vers le forum base de données pour creuser ce point-là.

  9. #9
    Membre confirmé
    Avatar de Higgins
    Inscrit en
    Juillet 2002
    Messages
    520
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 520
    Points : 543
    Points
    543
    Par défaut
    On m'a apporté une solution dans cette discussion
    Pour un puriste, la solution n'est pas idéale mais elle a le mérite de fonctionner

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [c#]Comment forcer la destruction d'un objet précédemment créé?
    Par Jayceblaster dans le forum Windows Forms
    Réponses: 5
    Dernier message: 24/07/2009, 14h29
  2. Réponses: 2
    Dernier message: 13/10/2007, 01h55
  3. destruction d'un objet
    Par akrobat dans le forum C++
    Réponses: 46
    Dernier message: 14/05/2006, 20h32
  4. Réponses: 1
    Dernier message: 09/07/2005, 18h16
  5. Réponses: 14
    Dernier message: 02/03/2005, 18h15

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