2014-07-15 3 views
0

J'ai un programme qui accepte une requête SQL en tant qu'argument de ligne de commande, interroge une base de données PostgreSQL et produit un fichier formaté de plusieurs façons (le plus souvent il est utilisé pour produire des fichiers CSV). Cependant, ce programme présente de sérieuses fuites de mémoire - avec une requête particulière qui produit un fichier de 12 Mo, le programme utilise 8 Go de RAM plus plusieurs Go d'espace de swap avant que le système d'exploitation ne le tue. Je veux trouver la cause de cette fuite de mémoire. Je ne connais pas très bien Delphi (et à en juger par la qualité du programme, pas plus que l'auteur original), mais je suis chargé de trouver une solution rapide.Delphi fuite de mémoire dans la chaîne?

La partie doData suivante de la sortie d'une seule ligne de l'ensemble de résultats. Je risque de deviner que le problème est avec la commande "copy" (créer une chaîne sur le tas qui n'est jamais libérée), mais je suis sûr que quelqu'un de plus expérimenté que moi pourra confirmer cette réponse ou me pointer la bonne direction.

procedure doData; 
var 
    s, fldVal : string; 
    i, fldLen : integer; 
begin 
    s := ''; 

    for i := 0 to ds.Fields.Count-1 do 
    begin 
     if (ds.Fields[i].DataType = ftDate) or 
      (ds.Fields[i].DataType = ftDateTime) then 
     begin 
      if psql.outDate = 'i' then 
       fldLen := 8 
      else 
       fldLen := 10; 

      if ds.Fields[i].IsNull then 
       fldVal := '' 
      else 
       fldVal := formatDate(ds.Fields[i].AsDateTime); 
     end 
     else 
     begin 
      fldLen := ds.Fields[i].DisplayWidth; 
      fldVal := ds.Fields[i].AsString; 
     end; 

     if (psql.outType = 'd') or (psql.outType = 's') then 
      s := s + trim(fldVal) 

     else if psql.outType = 'f' then 
     begin 
      s := s + fldVal; 

      if fldLen - length(fldVal) > 0 then 
       s := s + copy(spaces, 1, fldLen - length(fldVal)); 
       // Is this a memory leak above? 
     end; 

     if psql.outType = 's' then 
     begin 
      if i < ds.Fields.Count-1 then 
      s := s + psql.outDelimChar; 
     end 
     else 
      s := s + psql.outDelimChar; 
    end; 

    writeln(psql.outPrefixData + s); 
end; 
+1

Le type de chaîne Delphi est géré avec des comptages de référence. Lorsqu'une variable de chaîne est hors de portée, elle est automatiquement détruite. Le 'Copy' ne peut pas créer une fuite de mémoire dans ce code. –

+1

Si vous produisez une chaîne de 12 Mo, vous faites quelque chose de mal: utilisez plutôt TStringBuilder (ou écrivez directement dans un flux). Mais utiliser un code comme 's: = s + xx' est très mauvais pour la gestion de la mémoire – Daniel

+0

J'ai trouvé que' MadExcept' était un outil efficace pour identifier les fuites de mémoire, mais à partir de votre fragment de code je vérifierais probablement où 'ds' et 'psql' est libéré - vous pouvez avoir de la chance ... –

Répondre

4

Il n'y a pas de fuite dans ce code. Le type Delphi string est géré par le compilateur et ne nécessite aucune libération de mémoire explicite du programmeur.

Si vous souhaitez trouver votre fuite, vous devez inclure la version de débogage complète de FastMM. Cela produira des rapports de diagnostic de toute fuite dans votre code, y compris des traces de pile qui aident à identifier où la mémoire a été allouée à l'origine.