Démonstration de la gestion des objets en mémoire par delphi lors de leur création/destruction

Soyez le premier à donner votre avis sur cette source.

Vue 6 881 fois - Téléchargée 609 fois

Description

Rien de bien nouveau ici, j'espère que ça pourra toutefois aider certains à comprendre comment Delphi gère la mémoire associée aux objets (en complément au tutoriel http://www.delphifr.com/tutorial.aspx?ID=606).

En particulier cette petite démo montre l'ordre dans lequel les créateurs/destructeurs sont exécutés par Delphi (implicitement pour certains):
-NewInstance
-Constructeur
-AfterConstruction
-...
-BeforeDestruction
-Destructeur
-FreeInstance

En particulier le programme illustre comment lors de l'exécution de:
o:=TDemoClass.Create;
Delphi s'occupe de générer automatiquement du code pour appeler le destructeur en cas d'exception dans le constructeur (et ainsi libérer la mémoire allouée).

Hélas, un tel mécanisme n'existe pas pour le destructeur: si une exception est déclenchée dans le destructeur, la mémoire occupée par les champs de la classe n'est pas libérée automatiquement (La simulation de destruction proposée dans le programme gère toutefois correctement le problème). Avec l'écriture "standard" utilisant le destructeur, on a une fuite de mémoire de 1KB lorsque celui-ci provoque une exception. Ceci démontre entre autres la nécessité d'écrire des destructeurs "sécurisés" qui ne déclenchent pas d'exception.

Source / Exemple :


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TDemoClass=class(TObject)
    {Un champ bidon qui occupe 1KB}
    Field:array[0..1023] of Byte;
    
    constructor Create;
    destructor Destroy;override;

    procedure doCreate;
    procedure doDestroy;

    class function NewInstance:TObject;override;
    procedure FreeInstance;override;

    procedure AfterConstruction;override;
    procedure BeforeDestruction;override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TDemoClass }

{Le code ajouté dans le constructeur est regroupé dans doCreate pour ne pas avoir à passer par l'assembleur
 pour l'extraire}
constructor TDemoClass.Create;
begin
  doCreate;
end;

{Le code ajouté dans le destructeur est regroupé dans doDestroy pour ne pas avoir à passer par l'assembleur
 pour l'extraire}
destructor TDemoClass.Destroy;
begin
  doDestroy;
end;

class function TDemoClass.NewInstance: TObject;
begin
  ShowMessage('1 - Calling NewInstance'#13'    '+IntToStr(InstanceSize)+' Bytes will be allocated');
  Result:=inherited NewInstance;
end;

{Le code de doCreate devrait être écrit dans le constructeur, mais ça simplifie l'exemple de le mettre ici}
procedure TDemoClass.doCreate;
begin
  ShowMessage('2 - Calling Constructor');
  if Form1.CheckBox1.Checked then
    raise Exception.Create('Exception raised in constructor');
end;

procedure TDemoClass.AfterConstruction;
begin
  ShowMessage('3 - Calling AfterConstruction');
  inherited;
end;

procedure TDemoClass.BeforeDestruction;
begin
  ShowMessage('4 - Calling BeforeDestruction');
  inherited;
end;

{Le code de doDestroy devrait être écrit dans le destructeur, mais ça simplifie l'exemple de le mettre ici}
procedure TDemoClass.doDestroy;
begin
  ShowMessage('5 - Calling Destructor');
  if Form1.CheckBox2.Checked then
    raise Exception.Create('Exception raised in destructor');
end;

procedure TDemoClass.FreeInstance;
begin
  ShowMessage('6 - Calling FreeInstance'#13'    '+IntToStr(InstanceSize)+' Bytes will be unallocated');
  inherited;
end;

{ TForm1 }

{Simulation du code automatiquement généré par Delphi lors de la création "normale" d'un object}
procedure TForm1.Button1Click(Sender: TObject);
var
  o:TDemoClass;
  tmp:TObject;
begin
  tmp:=TDemoClass.NewInstance;
  try
    TDemoClass(tmp).doCreate;
    tmp.AfterConstruction;
  except
    tmp.Destroy;
    raise;
  end;
  o:=TDemoClass(tmp);
end;

{Création "normale" d'un object}
procedure TForm1.Button2Click(Sender: TObject);
var
  o:TDemoClass;
begin
  o:=TDemoClass.Create;
end;

{Ce que ne FAIT PAS Delphi: code pour libérer toutes les resources lors de la destruction, même en cas
 d'erreur dans le destructeur}
procedure TForm1.Button3Click(Sender: TObject);
var
  o:TDemoClass;
begin
  o:=TDemoClass.Create;
  try
    o.BeforeDestruction;
    o.doDestroy;
  finally
    o.FreeInstance;
  end;
end;

{Destruction "normale" d'un object: si une exception est levée dans le destructeur, la mémoire occupée par
 l'instance (en tout InstanceSize octets, ici au moins 1KB) n'est pas libérée}
procedure TForm1.Button4Click(Sender: TObject);
var
  o:TDemoClass;
begin
  o:=TDemoClass.Create;
  o.Destroy;
end;

end.

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

FENETRES
Messages postés
196
Date d'inscription
jeudi 15 juillet 2004
Statut
Membre
Dernière intervention
14 avril 2009
-
Pas à ma connaissance.
cs_Forman
Messages postés
600
Date d'inscription
samedi 8 juin 2002
Statut
Membre
Dernière intervention
6 avril 2010
1 -
Juste une question par rapport à ça, est-ce que ces composants ne sont pas des contrôles ActiveX tous les 3?
FENETRES
Messages postés
196
Date d'inscription
jeudi 15 juillet 2004
Statut
Membre
Dernière intervention
14 avril 2009
-
Bonjour,

Cette source est tellement d'actualité que ce n'est que récemment que les fuites de mémoire des contrôles TShellTreeView, TshellListView et TShellCombobox ont été identifiées par Borland (cf. adresse ci-dessous).

http://qc.codegear.com/wc/qcmain.aspx?d=8322

A+,
Nicolas___
Messages postés
1039
Date d'inscription
jeudi 2 novembre 2000
Statut
Membre
Dernière intervention
24 avril 2013
2 -
"Avec l'écriture "standard" utilisant le destructeur, on a une fuite de mémoire de 1KB lorsque celui-ci provoque une exception. "

C'est sur quand on voit comment Vista bouffe la ram , ya de quoi s'inquité pour 1KB de perdu :)

Tres interressant ... surtout quand on a la (mauvaise) habitude du java ou le destructeur n'existe pas ( Ou alors mes profs sont des Charltants ! )

Ciao

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.