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;
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. –
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
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 ... –