destructor TMyObject .Destroy
begin
// je supprime bien sur ts ce que j'ai pu creer ici, mais pr l'exemple, ca n'en vaut pas la peine ...
inherited Destroy;
end;
{ - TMyList ---------------------------------------------------------- }
constructor TMyList .Create;
begin
inherited Create(True);// OwnObject est a True, Donc libération des Objects Automatique !
end;
function TMyList .Get( Index : Integer ) : TMyObject;
begin
Result := inherited Get( Index );
end;
procedure TMyList .Put( Index : Integer; Item : TMyObject);
begin
inherited Put( Index, Item );
end;
procedure TAutreObject .RemoveAll;
var
i : integer;
begin
for i:=0 to MyList.Count-1 do begin
//Supprime un objet spécifié de la liste
// et (si OwnsObjects est à true) libère l'objet.
MyList.Rmove(MyList.Items[i]);
end;
MyList.Capacity := MyList.Count;
// Mais il ne supprime rien ! Enfin si , mon vecteur est vide
//mais ma mémoire est toujours autant occupée , prq ?!!
end;
Voila ben ma question est simple , Pourquoi ca ne me libère rien coté mémoire ?!
Nicolas___
Messages postés992Date d'inscriptionjeudi 2 novembre 2000StatutMembreDernière intervention24 avril 20132 2 févr. 2009 à 18:05
Bon ça y est ,
j'ai résolu mon problème et attention c'était encore plus con que tous , et ça prouve qu'il faut toujours faire gaffe au(x) message(s) d'erreur(s)
J'avais ceci mais je ne faisait jamais très attention :
[Avertissement] La méthode 'Destroy' cache la méthode virtuelle du type de base 'TObject'
Nicolas___
Messages postés992Date d'inscriptionjeudi 2 novembre 2000StatutMembreDernière intervention24 avril 20132 28 janv. 2009 à 14:36
Parce que ici je ne montre pas ts le code
(il est un peu long) ,
et que je ne dois pas effacer toute la liste , juste un certain nombre objet de la liste avec un Tag spécial ...
(Dans mon RemoveAll j'ai une condition , et si elle est a true -> Remove )
J'ai l'instruction TAutreObject.Clear qui appele tous simplement MyList.Clear , mais la encore , ce n'est aps libéré !
(J'ouvre le gestionnaire de tâches en même tps, je créé +- 500 object , ma mémoire occupée grimpe et quand je fais un Clear ou un RemoveAll, pas de différences , mais pourtant mon vecteur est vide ... )
Vous n’avez pas trouvé la réponse que vous recherchez ?
Nicolas___
Messages postés992Date d'inscriptionjeudi 2 novembre 2000StatutMembreDernière intervention24 avril 20132 28 janv. 2009 à 15:08
Pack
Supprime tous les éléments nil (Delphi) ou NULL (C++) du tableau Items.
Description
La méthode Pack déplace tous les éléments non-nil (Delphi) ou non-NULL (C++) au début du tableau Items, puis réduit la propriété Count au nombre d'éléments réellement utilisés. Pack ne libère pas la mémoire utilisée pour stocker les pointeurs nil (Delphi) ou NULL (C++). Pour libérer la mémoire allouée aux entrées inutilisées qui sont supprimées par Pack, affectez la nouvelle valeur de Count à la propriété Capacity.
Donc j'ai fais ca :
procedure TAutreObject .RemoveAll;
var
i : integer;
begin
for i:=0 to MyList.Count-1 do begin
MyList.Items[i] := nil;
end;
MyList.Pack;
MyList.Capacity := MyList.Count;
end;
Ca ne change rien !
Et quand je veux faire
procedure TAutreObject .RemoveAll;
var
i : integer;
begin
for i:=0 to MyList.Count-1 do begin
MyList.Items[i] .free;// Forcement ca plante royalement !
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20122 28 janv. 2009 à 15:32
Moi j'aurais plutôt écrit quelquechose comme :
procedure TAutreObject .RemoveAll;
var
i : integer;
begin
for i:=0 to MyList.Count-1 do
begin
MyList.Remove(MyList.Items[i]);
MyList.Items[i] := nil; // Assignation à nil après la libération.
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 28 janv. 2009 à 17:25
Salut Nicolas.
for i:=0 to MyList.Count-1 do
begin
//Supprime un objet spécifié de la liste
// et (si OwnsObjects est à true) libère l'objet.
MyList.Remove(MyList.Items[i]);
asm DEC I end;
end;
Faut utiliser l'asm sinon Delphi va grogner. Chez moi, 50000 éléments, application passe à 8000Ko mémoire, après RemoveAll, retombe à 4000.
La raisonest que quand tu supprime un objet, Count est automatiquement décrémenté : donc, tu te retrouves avec une belle V.A, et aucune libération.
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 28 janv. 2009 à 21:51
Ok, je m'en souviendrai, ça pourrait peut-être m'aider ce conseil.
Bon ... sinon ça marche si on recule de 1 à chaque fois ?
Sinon tu peux partir de la fin, ça marche aussi et sans asm.
for i:= 0 to liste.Count - 1 do
liste.Remove(liste[i]);
Première boucle. liste.Count vaut 3, i vaut zéro :
liste.Remove(liste[0]);
[Aide de Delphi]
Appelez Remove pour supprimer un objet spécifique de la liste lorsque l'indice est inconnu. La valeur renvoyée est l'indice de l'objet dans le tableau Items avant qu'il ne soit supprimé. Si l'objet spécifié n'est pas trouvé dans la liste, Remove renvoie –1. Si OwnsObjects est à True, Remove libère l'objet en plus de le supprimer de la liste.
Après qu'un objet a été supprimé, tous les objets qui suivent sont déplacés et Count est décrémenté.
de Delphi
Donc le contenu de liste devient :
liste[0] = titi;
liste[1] = toto;
Bin oui, tata est libéré, titi et toto sont déplacés (Déplacement de pointeur, coûte pas grand chose).
Deuxième boucle. liste.Count vaut 2, i vaut 1 :
liste.Remove(liste[1]);
contenu de liste après Remove :
liste[0] = titi;
et on sort de la boucle.
Bilan titi n'est pas libéré.
Il faut par exemple coder ça comme ça :
procedure TAutreObject .RemoveAll;
var
nCount: Integer;
i: Integer;
begin
nCount:= MyList.Count;
for i:= 0 to nCount - 1 do
MyList.Remove(MyList.Items[0]);
end;
Remarquez le 0 : on supprime toujours le premier élément de la liste et les autres se décalent. Le deuxième (1) devient premier (0) et est supprimé au tour suivant. Remarquez aussi la récupération de count dans une vériable afin d'empècher la réévaluation.
Mais côté perf, c'est tout pourri. Il vaut bien mieux attaquer à la fin de la liste, pour éviter les décalages :
procedure TAutreObject .RemoveAll;
var
i: Integer;
begin
for i:= nCount - 1 downto 0 do
MyList.Remove(MyList.Items[i]);
end;
Ainsi on supprime toujours le dernier élément.
Finalement, une petite remarque concernant Windows ou le gestionnaire des tâche qui dit que la mémoire n'est pas rendu. C'est vrai : Windows ne la pas vraiment récupéré, et ne peut pas la réaffecter à un autre processus.
C'est à cause des pages. La mémoire est divisée en pages de 4 ko. C'est l'unité de mémoire que Windows peut donner à un processus. Les allocations sont réalisées par VirtualAlloc. Après, par dessus ça, vient un tas, fourni par Windows (HeapAlloc, GlobalAlloc, LocalAlloc...) ou par le langage : Delphi propose certainement son propre tas.
En interne, le tas peut utiliser un autre tas, mais au final, c'est VirtualAlloc qui est utilisé et qui ne peut que délivrer 4 ko, rien, ou un multiple de 4ko.
Les tas subdivise les pages qui lui sont données. Supposons que l'on demande deux variables de 2 ko. Le tas peut demander une page de 4 ko, et stocker les deux dedans. Problème si une des deux variables est libérée, la page ne peut être rendu au système : la moitié est encore utilisée. Donc le processus consomme toujours 4 ko dans le gestionnaire des tâches, alors qu'il a libéré la moitié de sa mémoire ! Par contre, le tas sait que la moitié vide est vide, et peut la réutiliser pour des demandes ultérieures.
C'est ainsi que sur une application qui tourne depuis longtemps, un grand nombre de pages peut être bouffé par une ou deux variables qui restent dessus. Le processus à l'air donc de consommer beaucoup de mémoire, alors qu'en fait la plupart de sa mémoire allouée est vide.
L'utilisation de pages par le système n'est pas du tout spécifique à Windows, mais est dûe à l'architecture du processeur et du fait que la mémoire est virtualisée : chaque processus à son propre espace, et il faut tout traduire en adresse physique à chaque accès. Il y a des tables de traduction page virtuelle -> page physique utilisées par le processeur, bien que gérées par Windows.
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 29 janv. 2009 à 15:04
@rt15
« Windows ne la pas vraiment récupéré, et ne peut pas la réaffecter à un autre processus »
- Imaginons une application qui doit créer de très nombreux objets et les libérer presque aussitôt. Si on n'a pas bcp de chance, ne risque t-on pas d'arriver à un plantage du système, même si le code est irréprochable du côté des libérations
- Existe t-il un moyen ou une méthode de codage pour se prémunir de ça
cs_rt15
Messages postés3874Date d'inscriptionmardi 8 mars 2005StatutModérateurDernière intervention 7 novembre 201413 29 janv. 2009 à 15:49
Pour le parallèle avec le dur, je n'en sais rien, je ne sais pas comment ça fonctionne exactement.
Tu peux effectivement te retrouver avec un processus qui consomme beaucoup plus de mémoire qu'il n'en utilise vraiment, avec effectivement un genre de fragmentation.
Mais il n'y a aucun moyen de défragmenter en Delphi, car on ne peut travailler qu'au niveau page. Suppose que tu as obj1 dans page1 et obj2 dans page 2 tels que obj1 et obj2 puissent tenir dans la même page.
Tu voudrais mettre obj1 et obj2 dans page1 et rendre page2 au système. Tu aurais effectivement l'impression de défragmenter.
Le problème c'est que le programme à qui appartient obj2 "perd" obj2. Par exemple obj2 était dans une ObjectList. Une ObjectList est en gros un tableau de pointeurs sur les objets. Donc dans ton ObjectList, si tu as l'impression d'avoir obj1 et obj2, tu as un tableau avec deux adresse, celles d'obj1 et celle d'obj2.
Si tu déplace obj2 sans mettre à jour ton ObjectList, l'adresse contenue dans la liste pointera toujours sur la page mémoire libérée -> violation d'accès lors du prochain accès à obj2.
Le problème est plus profond que ça : il n'y a pas besoin d'ObjectList. Le langage machine est fondamentalement basés sur les adresses et n'arrête pas de les manipuler. Si des objets, structures ou variables sont déplacées, tout planterais.
Après, il existe des langages plus abstraits ou on manipule pas vraiment des pointeurs, mais plutôt des pointeurs sur des pointeurs. A ce moment là, on peut défragmenter la mémoire en corrigeant les pointeurs. C'est ce qui est fait en Java il me semble. Mais ce système n'est pas sans inconvénients, sur le plan des perfs notamment.
On peut imaginer des techniques et des structures de données pour limiter la fragmentation. Par exemple en utilisant des tableaux et en recopiant le dernier élément dans l'élément que l'on supprime. Le problème étant que l'ex dernier élément n'a plus le même indice dans le tableau, donc il faut gérer cela, etc...