Fuite mémoire avec StringGrid

Stauf Messages postés 5 Date d'inscription lundi 25 février 2002 Statut Membre Dernière intervention 27 février 2002 - 25 févr. 2002 à 15:57
rekia2004 Messages postés 1 Date d'inscription mercredi 14 avril 2004 Statut Membre Dernière intervention 1 mai 2004 - 1 mai 2004 à 18:10
Bonjour,

J'ai le problème suivant:
Je crée dynamiquement des données puis libère l'espace une fois affichées. Jusque là, pas de soucis, l'espace est alloué puis libéré.
Maintenant, je lance une fenêtre espion dans laquelle j'affiche lesdites données dans un StringGrid... et là, ça va plus : l'espace n'est plus libéré ou pas à chaque coup.
Résultat, mon application grossit, grossit jusqu'à exploser la mémoire virtuelle.

Là où c'est riglo, c'est quand j'iconifie mon application : Le volume mémoire pris par l'application revient à un seuil très bas.
Puis si je la re-maximize, elle reprend son niveau initial puis grossit, grossit...

Pour être tranquille, j'initialise le nombre de lignes de mon stringGrind à 10000 lignes. Quand j'ouvre la fenêtre, je vois bien l'alocation mémoire associée, mais rien n'y fait:
La mémoire grossit alors que je n'ajoute pas de ligne : j'écris dans les 10000 premières lignes...

Note : Je travaille sous Delphi 5.0

Bon, ben là j'y comprends rien !! :question)

Merci de m'aider.

10 réponses

cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
25 févr. 2002 à 18:57
Ben, personnellement, je ne chercherais pas à afficher 10000 lignes dans un stringgrid !
Les bases de données font faites pour gérer de gros volumes de données et un TDbGrid pour n'en n'afficher qu'une partie : celle qui est visible.
Utiliserais-tu des tableaux dynamiques, par hasard ?
Donnes un peu plus de détails si tu veux que l'on t'aide.
0
Stauf Messages postés 5 Date d'inscription lundi 25 février 2002 Statut Membre Dernière intervention 27 février 2002
26 févr. 2002 à 08:40
Bon, alors allons-y pour plus de détails et merci de s'intéresser à mon problème.

Je crée dynamiquement des structures dans un Thread, thread qui est chargé de faire l'acquisition de données sur une ligne série.

Une fois les données collectées, je passe le pointeur de cette structure :
- à une fonction de ma fenêtre espion, qui l'utilise pour remplir le StringGrid de la manière suivante :

MyStringGrid.Cells[0, i] := IntToHex(p^.donnees);

où MyStringGrid est le StringGrid où je veux afficher les données que je reçois chaque seconde,
i, l'indice de la ligne, compris entre 1 et 10000 (pour mémoire, le stringgrid est initialisé à 10000 lignes)
p le pointeru passé en paramètre de la procédure.

- à un autre Thread qui se charge de différents affichages puis qui libère l'espace alloué en faisant un:
p^.Free();
Dispose(p);

Peut-être d'autres infos :
J'initialise le StringGrid de la manière suivante:
MyStringGrid.RowCount := 10000;

La mémoire diminue beaucoup quand j'iconifie : Je pensais que ça aurait donc pu être dû à une sorte de mémoire vidéo alloué par Windows ?

J'avoue que je débute en programmation Windows et je ne connaissais pas Delphi auparavant. J'ai repris le code existant, qui utilisait le StringGrid. Il y aurait donc des objets plus adaptés pour ce genre d'application?
Je vais déjà éplucher l'aide sur les TBdGrid....

Merci.
0
PhGORMAND Messages postés 54 Date d'inscription jeudi 3 janvier 2002 Statut Membre Dernière intervention 20 juillet 2006
26 févr. 2002 à 11:26
Salut. Je ne saisis par tout le problème, mais il y a deux choses qui me choquent :
1 - En général, pour liberer un pointeur, on utilise
l'instruction NIL plutot que FREE -> P := Nil;

2 - Résever 10000 ligne d'office pour un StringGrid, est abérant. Une bonne gestion de la mémoire doit se faire de façon dynamique tant que c'est possible.
Donc un StringGrid étant une collection de pointeur sur des objet de type TEdit, il est de loin préférable, de créer une nouvelle ligne seulement si on en a besoin.
Ex : StringGrid1.RowCount := StringGrid1.RowCount + 1;

Ou bien StringGrid1.RowCount := NbLignesFichier + 1;

A+
0
Stauf Messages postés 5 Date d'inscription lundi 25 février 2002 Statut Membre Dernière intervention 27 février 2002
26 févr. 2002 à 11:58
Autant pour moi :
Je fais en fait :
p^.free(); // Je libère la structure pointée par p
Dispose (p);
p:=nil;

Quant au 10000 lignes, c'est une exigence du client. De toutes façons, j'ai besoin de toutes ces lignes ! Au bout de 10000 lignes, je n'ai pas trouvé d'autre moyen que de recopier les 9000 dernières lignes en haut du StringGrid, de manière à avoir dans le StringGrid au moins les 9000 dernières lignes reçues.
Y a-t-il un moyen de gérer plus élégamment la mémoire ?
En fait, ce qu'il me faut dans cette fenêtre espion, c'est afficher des lignes de données (les 10000 plus récentes reçues... avec une barre de défilement bien sûr) et sans perte de mémoire !!!

Autre question : Comment libérer de la mémoire allouée dans un StringGrid par la propriété RowCount ?

Si vous avez d'autres idées pour réaliser cela, je suis preneur...

Merci
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
PhGORMAND Messages postés 54 Date d'inscription jeudi 3 janvier 2002 Statut Membre Dernière intervention 20 juillet 2006
26 févr. 2002 à 16:19
Ce qui est bizard, c'est qu'il n'y a pas de plantage avec P^.Free; puis Dispose(P);

Free est une methode d'objet qui detruit l'objet et libere la mémoire qui lui est associé. Il est précisé dans l'aide de DELPHI, qu'on ne doit pas utiliser Dispose avec Free ou Create.

"Dispose" ne doit etre utilisé seulement si on a aloué de la mémoire avec "New".

En principe on ne peut utiliser Free seulement avec Nil ( c'est pas obligatoire ) . Nil signifit simplement que le pointeur ne pointe sur rien, mais j'avoue que je n'ai jammais trouvé très claire les explications de l'aide.

Ce que je sais pas expérience, c'est que l'on peut faire
P.Free;
P:=Nil;
mais pas l'inverse.

Free doit être utilisé avec Create et jammais avec Dispose.

Dispose doit être utilisé avec New, FreeMem, GetMem.

Le plantage mémoire n'est pas systématique, si on ne perturbe pas l'espace d'autres données ou d'autres objets, mais on peut imaginer les conséquences sur une grosse application.

Quand à la libération mémoire d'une stringGrid.
En principe, le seul fait de changer le nombre de ligne ( propriété RowCount ) alloue ou libère la mémoire automatiquement, car la propriété appelle une procédure d'allocation de mémoire ( vive la VCL ). Alors 10000 lignes pourquoi pas, mais de combien de données chacunes ?

Je ne connais pas le cahier des charges de ton programme, mais le role d'un programmeur est aussi d'expliquer et de convaincre son client qu'il peut y avoir d'autre solutions (j'en sais quelque chose ) pour que cela fonctionne. A condition d'apporter une solution pratique bien sur.

A+
0
Stauf Messages postés 5 Date d'inscription lundi 25 février 2002 Statut Membre Dernière intervention 27 février 2002
26 févr. 2002 à 16:51
J'ai pas mal galéré avec les new, dispose, free et autres destroy...
Moi non plus, je ne trouve pas l'aide bien bien claire...
Pour être complet, voici ce que je fait:

Dans mon thread d'acquisition:

// Création du pointeur sur la structure de données
New(PData);

// Création de la structure de données
PData^ := T_ThreadIO_Data.Create();

// Ensuite je remplis ma structure de données

// Puis, je passe le pointeur à ma fenêtre espion (qui s'appelle spy, si, si)
G_SpyDlg.AddData(PData);

// Et enfin, j'empile le pointeur dans une pile d'échange sécurisée par mutex entre mon thread d'acquisition et mon thread d'affichage

Dans la fenêtre espion, j'ai:
procedure T_SpyDlg.AddData(p : T_PThreadIO_Data); // T_PThreadIO_Data est le type "pointeur sur la structure de donnees"
begin
...
MyStringGrid.Cells[0, i] := IntToHex(p^.donnee_D ...);

...
end;

Et dans mon thread d'affichage, j'ai :

// extraction d'un pointeur de la pile sécurisée
pData:= Queue.ExtractData();

if (nil <> pData) then
begin
UpdateDisplay(pData);
pData^.Free();
dispose(pData);
pdata:=nil;
end;

Voilà en gros... Et ça, ça plante pas !

Tu préconises P.Free, mais est-ce que àa libère l'espace correspondant à la structure pointée par P ?

Quant aux relations avec le client ...
Non, mais, il a un besoin assez simple : une bête fenêtre espion... Ca devrait pouvoir se faire, non ?
Il veut pouvoir visualiser environ 1/4 d'heure de données reçues. Il y a environ 80 caractères par ligne, une structure de données faisant à peu près une dizaine de lignes...

Merci

A bientôt j'espère...
0
PhGORMAND Messages postés 54 Date d'inscription jeudi 3 janvier 2002 Statut Membre Dernière intervention 20 juillet 2006
27 févr. 2002 à 10:59
Dans mon message précédent, j'expliquai que Free doit être utilisé conjointement avec Create, (methode objet), et Dispose seulement avec New. Sur ce point, l'aide de DELPHI est très claire.

Je n'ai pas encore le temps d'examiner le code, mais si c'est pour garder une trace des donnéees reçues, il me parrait plus judicieux et plus simple d'utiliser un listbox, ou une StringList pour cumuler les données :

ListBox1.Items.Add(ChaineDeDonnees);
If ListBox1.Items.Count > 10000 Then
ListBox1.Items.Delete(0);

Si on veut voir le numero de donnée de chaque ligne, on peut ajouter ce numéro :

ChaineDeDonnees := IntToStr(Ligne) + ' - ' + ChaineDeDonnees;

Au fait, pData c'est quel type de structure ?

A+
0
Stauf Messages postés 5 Date d'inscription lundi 25 février 2002 Statut Membre Dernière intervention 27 février 2002
27 févr. 2002 à 11:17
La solution de la TListBox me semble intéressante (surtout pour supprimer les premières lignes). Le seul petit problème est que j'ai plusieurs colonnes de données, mais je peux le contourner en mettant autant de TListBox que de colonnes.

Pour répondre à la question:
PData est du type T_PThreadIO_Data, c'est-à-dire pointeur sur le type T_ThreadIO_Data, qui est une structure de données.

Merci bien, je vais tester tout de suite la TListBox...

A+
0
PhGORMAND Messages postés 54 Date d'inscription jeudi 3 janvier 2002 Statut Membre Dernière intervention 20 juillet 2006
28 févr. 2002 à 09:25
Bon ! Je crois que je n'ai pas tout compris.

1 - Ta structure pData, c'est quoi exactement ?
2 - As tu vraiment besoin de déclarer P comme pointeur ?
3 - Est ce que tu ne mélanges pas les pointeurs et les classes, New et Create ?
4 - Alors si tu dois afficher des données differentes, effectivement la StringGrid peut être préférable.
5 - Si tu donnes les infos au compte goute, c'est plus difficile de répondre.

Je veux bien me pencher sur ton problème à tête reposée, il m'intéresse. Alors envois moi ton source complet.

EMail : philippe.gormand@free.fr

URL : http://philippe.gormand.free.fr/
0
rekia2004 Messages postés 1 Date d'inscription mercredi 14 avril 2004 Statut Membre Dernière intervention 1 mai 2004
1 mai 2004 à 18:10
bonjour...
je voudrais des informations sur l'utilisation de composant stringgrid en delphi5 en particulièrement comment faire la saisie dans ce composant (c.a.d rentrer des données concernant un dessin (canvas) par exemple le réseau de pétri .....)
merci en avance...
0
Rejoignez-nous