0

Je crée un nouveau composant qui hérite de TClientDataSet et provoque une fuite de mémoire. J'ai créé une démo pour reproduire l'erreur (sans avoir besoin de partager myCustomComponent). Comment puis-je résoudre ce problème de fuite de mémoire?TClientDataSet CreateDataset Memory Leak

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    ClientDataSet1.Close; 
    ClientDataSet1.Tag := 1; 
    ClientDataSet1.Open; 
end; 

procedure TForm1.ClientDataSet1BeforeOpen(DataSet: TDataSet); 
begin 
    if ClientDataSet1.Tag = 1 then 
    begin 
     ClientDataSet1.Tag := 0; 
     ClientDataSet1.Fields.Clear; 
     ClientDataSet1.FieldDefs.Clear; 
     ClientDataSet1.FieldDefs.Add('Collection', ftString, 50); 
     ClientDataSet1.FieldDefs.Find('Collection').CreateField(ClientDataSet1); 
     ClientDataSet1.CreateDataSet; 
    end; 
end; 

FastMM Event Log Fichier:

--------------------------------2017/6/19 12:00:21-------------------------------- 
A memory block has been leaked. The size is: 68 

This block was allocated by thread 0x4FA8, and the stack trace (return addresses) at the time was: 
418CD6 [FastMM4.pas][FastMM4][DebugAllocMem$qqri][9900] 
407276 [System.pas][System][AllocMem$qqri][4557] 
65F91B [Datasnap.DBClient.pas][Datasnap.DBClient][Dbclient.TCustomClientDataSet.AllocKeyBuffers$qqrv][3965] 
6598AE [Datasnap.DBClient.pas][Datasnap.DBClient][Dbclient.TCustomClientDataSet.InternalOpen$qqrv][1514] 
623BC8 [Data.DB.pas][Data.DB][Db.TDataSet.DoInternalOpen$qqrv][12527] 
623C77 [Data.DB.pas][Data.DB][Db.TDataSet.OpenCursor$qqro][12556] 
65885B [Datasnap.DBClient.pas][Datasnap.DBClient][Dbclient.TCustomClientDataSet.OpenCursor$qqro][1282] 
623B2F [Data.DB.pas][Data.DB][Db.TDataSet.SetActive$qqro][12508] 
62396B [Data.DB.pas][Data.DB][Db.TDataSet.Open$qqrv][12464] 
65BE16 [Datasnap.DBClient.pas][Datasnap.DBClient][Dbclient.TCustomClientDataSet.CreateDataSet$qqrv][2342] 
706827 [Unit1.pas][Unit1][TForm1.ClientDataSet1BeforeOpen$qqrp16Data.Db.TDataSet][64] 

The block is currently used for an object of class: Unknown 

The allocation number is: 1092 

Current memory dump of 256 bytes starting at pointer address 7EF776F0: 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F1 7F B4 7C 
80 80 80 80 80 80 80 80 00 00 00 00 C1 70 F7 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
73 04 00 00 D6 8C 41 00 76 72 40 00 1B F9 65 00 AE 98 65 00 C8 3B 62 00 77 3C 62 00 5B 88 65 00 
2F 3B 62 00 6B 39 62 00 F4 65 70 00 D5 A7 53 00 A8 4F 00 00 A8 4F 00 00 AA 72 40 00 BE F5 60 00 
AF F9 65 00 FA 9A 65 00 B8 3C 62 00 06 8C 65 00 9C 3B 62 00 F7 31 62 00 3C 8B 41 00 51 8B 41 00 
29 7A 65 00 3C 00 00 00 00 00 00 00 69 F3 D9 86 E4 FB 71 00 80 80 80 80 80 80 80 80 80 80 80 80 
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . ñ ´ | 
€ € € € € € € € . . . . Á p ÷ ~ . . . . . . . . . . . . . . . . 
s . . . Ö Œ A . v r @ . . ù e . ® ˜ e . È ; b . w < b . [ ˆ e . 
/; b . k 9 b . ô e p . Õ § S . ¨ O . . ¨ O . . ª r @ . ¾ õ ` . 
¯ ù e . ú š e . ¸ < b . . Œ e . œ ; b . ÷ 1 b . < ‹ A . Q ‹ A . 
) z e . < . . . . . . . i ó Ù † ä û q . € € € € € € € € € € € € 
€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € 

Lorsque vous essayez le code de l » @victoria je reçois ci-dessous erreur (althoug ReportMemoryLeaksOnShutdown ne soulève rien) de FastMM alors j'ai réalisé FastMM me confondre. J'ai réintroduit la méthode Open et déplacé ce code là (sans appeler inherited ou Open) et ReportMemoryLeaksOnShuntdown ne montre aucune fuite mais je ne pouvais pas comprendre pourquoi FastMM se lève.

enter image description here

A memory block has been leaked. The size is: 68 

This block was allocated by thread 0x4918, and the stack trace (return addresses) at the time was: 
4DB29E54 
4DB28419 
4DB21AA9 
4DB1FB5B 
7711F11C [VirtualQuery] 
33B8FD9 [GetFrameBasedStackTrace] 
33B901C [GetFrameBasedStackTrace] 
77983431 [Unknown function at RtlQueryPerformanceCounter] 
33B9336 [GetRawStackTrace] 
417A0E [FastMM4.pas][FastMM4][CalculateHeaderCheckSum$qqrp29Fastmm4.TFullDebugBlockHeader][9080] 
417A1D [FastMM4.pas][FastMM4][UpdateHeaderAndFooterCheckSums$qqrp29Fastmm4.TFullDebugBlockHeader][9090] 

The block is currently used for an object of class: Unknown 

The allocation number is: 1060 

Current memory dump of 256 bytes starting at pointer address 7EF76FA0: 
3C 00 B4 4D 08 00 00 00 00 00 00 00 00 00 00 00 3F 00 00 00 00 80 80 80 80 80 80 80 80 80 80 80 
80 80 80 80 80 80 80 80 43 00 80 80 80 80 80 80 80 80 80 80 80 80 80 80 01 00 00 00 0F 00 00 00 
8C A3 AB 60 80 80 80 80 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
45 04 00 00 E8 A1 40 00 A3 AC 40 00 B5 F6 40 00 A0 BD 65 00 79 68 70 00 D5 A7 53 00 47 1F 55 00 
55 2A 55 00 65 A2 53 00 38 70 3F 75 DD B4 04 74 18 49 00 00 18 49 00 00 AA 72 40 00 85 A2 40 00 
3B BE 65 00 79 68 70 00 D5 A7 53 00 47 1F 55 00 55 2A 55 00 65 A2 53 00 38 70 3F 75 DD B4 04 74 
89 B5 04 74 1B 00 00 00 E9 FD 01 00 04 D3 19 CB E4 FB 71 00 80 80 80 80 80 80 80 80 80 80 80 80 
80 80 80 80 80 80 80 80 80 80 80 FB 2C E6 34 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 
< . ´ M . . . . . . . . . . . . ? . . . . € € € € € € € € € € € 
€ € € € € € € € C . € € € € € € € € € € € € € € . . . . . . . . 
Œ £ « ` € € € € . . . . . . . . . . . . . . . . . . . . . . . . 
E . . . è ¡ @ . £ ¬ @ . µ ö @ .   ½ e . y h p . Õ § S . G . U . 
U * U . e ¢ S . 8 p ? u İ ´ . t . I . . . I . . ª r @ . … ¢ @ . 
; ¾ e . y h p . Õ § S . G . U . U * U . e ¢ S . 8 p ? u İ ´ . t 
‰ µ . t . . . . é ı . . . Ó . Ë ä û q . € € € € € € € € € € € € 
€ € € € € € € € € € € û , æ 4 € € € € € € € € € € € € € € € € € 
+0

On dirait que l'ensemble de données est ouvert deux fois. Vous auriez dû vous rendre compte que quelque chose n'allait pas avec votre code lorsque vous avez rencontré le débordement de pile qui a conduit à votre hack de ré-entrée Tag. Quant à savoir quelle est la solution, difficile à dire. J'imagine que vous avez juste besoin de sortir ce code de 'OnBeforeOpen' et de le placer avant l'appel' Open'. Débarrassez-vous de ce hack "Tag". Et lorsqu'un gestionnaire d'événements vous passe une instance, utilisez-le plutôt que d'utiliser le champ de la classe. –

+0

Vous créez un dataset et l'ouvrez. Ne l'ouvrez pas et avant de l'ouvrir, créez-le. – Victoria

+0

J'ai surévalué la procédure DoBeforeOpen J'utilise le code qui est écrit dans BeforeOpen dans cette section. Je ne veux pas que les programmeurs appellent CreateDataSet en externe, donc je veux le mettre dans ma méthode DoBeforeOpen des composants. –

Répondre

3

Ne pas définir et créer votre ensemble de données dans le BeforeOpen événement. Pour créer (et ouvrir) en mémoire dataset faire:

procedure TForm1.ButtonCreateClick(Sender: TObject); 
begin 
    ClientDataSet1.Close; 
    ClientDataSet1.FieldDefs.Clear; 
    ClientDataSet1.FieldDefs.Add('ID', ftInteger); 
    ClientDataSet1.FieldDefs.Add('Collection', ftString, 50); 
    ClientDataSet1.CreateDataSet; 
end; 

Pour ajouter enregistrements ne:

procedure TForm1.ButtonAppendClick(Sender: TObject); 
begin 
    ClientDataSet1.Append; 
    ClientDataSet1.FieldByName('ID').AsInteger := 1; 
    ClientDataSet1.FieldByName('Collection').AsString := 'My collection'; 
    ClientDataSet1.Post; 
end; 

Pour modifier enregistrement en cours faire:

procedure TForm1.ButtonUpdateClick(Sender: TObject); 
begin 
    ClientDataSet1.Edit; 
    ClientDataSet1.FieldByName('Collection').AsString := 'My collection upd.'; 
    ClientDataSet1.Post; 
end;