IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lazarus Pascal Discussion :

Vider un bloc mémoire [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Membre du Club
    Homme Profil pro
    Inscrit en
    février 2009
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations forums :
    Inscription : février 2009
    Messages : 34
    Points : 55
    Points
    55
    Par défaut Vider un bloc mémoire
    Bonjour à tous,
    Je souhaite savoir comment il est possible de vider (pas libérer) un bloc mémoire (alloué avec GetMem) de toutes les valeurs qui y sont stockés. Le code de l'objet est TBaseCtn.Clear. Je sais q'un FreeMem suivi d'un GetMem va fonctionner mais existe-t-il une autre solution? car j'ai également un souci avec la fonction TBaseCtn.Delete pour la suppersion d'un segment du bloc mémoire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    { TBaseCtn }
      PBaseCtn = ^TBaseCtn;
      TBaseCtn = Object
      private
        // Capacité de stockage du tableau en nb d'éléments{ 4 bytes }
        FCapacity        : PtrUInt;
        // Nombre d'éléments actifs du tableau             { 4 bytes }
        FCount           : PtrUInt;
        // Structure TypeInfo                              { 4 bytes }
        //FElTypeInfo      : PTypeInfo;
        // taille en bytes des éléments du tableau         { 2 bytes }
        FElementSize     : Word;
        // Pointeur tableau dynamique                      { 4 bytes }
        FMemStart      	 : pointer;
        // Pointeur vers le curseur de navigation
        FMemCursor			 : Pointer;
      protected
        { SetCapacity : Màj la capacité de stockage du tableau }
        procedure SetCapacity( aNewCapacity : PtrUInt);  {$ifdef HASINLINE}inline;{$endif}
        { Expand : Elargit la taille en mémoire  }
        procedure Expand;
        { Get : Retourne pointeur vers l'éléement de l'index demandé }
        function  Get(aIndex: PtrUInt): Pointer; 			 	{$ifdef HASINLINE}inline;{$endif}
        { Put : Initie le pointeur de l'élement demandé }
        procedure Put(aIndex: PtrUInt; aElementPtr: Pointer);
      public
        { Init : Initialisation du tableau et de la taille de l'élément à stocker }
        procedure Init(aCapacity: PtrUInt; aElementSize: Word);
    		{ Free : Libére la mémoire et RAZ les variables du conteneur}
        procedure Free;
     
        { Add : Ajoute un élément en fin de tableau }
        function  Add(const Element): PtrUInt;            {$ifdef HASINLINE}inline;{$endif}
        { Insert : Insére un élément à l'index passé en paramétre }
        procedure Insert(aIndex : PtrUInt; const aElement);{$ifdef HASINLINE}inline;{$endif}
        { Clear : Vider le tableau en désallouant le pointeur en mémoire }
        function  Clear: Boolean;
        { Delete : Supprime un élément du tableau selon l'index informé }
        function  Delete(aIndex: PtrUInt): Boolean;        {$ifdef HASINLINE}inline;{$endif}
     
        { Capacity : Determine la capacité de sockage du tableau }
        property  Capacity      : PtrUInt read FCapacity write SetCapacity;
        { Count : Retourne le nombre d'élements stockés dans le tableau}
        property  Count         : PtrUInt read FCount;
        { Items : Determine le pointeur de stockage pour l'indice demandé }
        property Items[aIndex: PtrUInt]: Pointer read Get write Put; // default;
      end;
     
    implementation
     
    { TBaseCtn }
    procedure TBaseCtn.SetCapacity(aNewCapacity: PtrUInt);
    begin
      if aNewCapacity = FCapacity then exit;			{ si la taille ne change pas alors sortie }
      if aNewCapacity = 0 then                    { Si nouvelle taille = 0 alors }
         Clear                                    { On vide la memoire }
      else
      begin
        if not Assigned(FMemStart) then           { Si le tableau n'existe pas }
          GetMem(FMemStart, aNewCapacity * FElementSize)	 { On affecte la mémoire à la taille demandée}
        else																			{ sinon ... }
          ReAllocMem(FMemStart, aNewCapacity * FElementSize); { On modifie la taille du tableau }
        FCapacity := aNewCapacity;                { Capacité = taille demandée }
      end;
    end;
     
    procedure TBaseCtn.Expand;
    begin
     
    end;
     
    function TBaseCtn.Get(aIndex: PtrUInt): Pointer;
    begin
    //  Result := nil;                    { Initie le resultat à nul }
    //  if (aIndex > FCount-1) then exit; { Si index est sup. au nombre d'elemenets alors exit }
    	Result := Pointer(PtrUInt(FMemStart)+(aIndex*FElementSize));
    end;
     
    procedure TBaseCtn.Put(aIndex: PtrUInt; aElementPtr: Pointer);
    begin
      Move(aElementPtr^, (FMemStart+(aIndex * FElementSize))^, FElementSize);
    end;
     
    procedure TBaseCtn.Init(aCapacity: PtrUInt; aElementSize: Word);
    begin
      if (aCapacity < 1) or (aElementSize < 1) then Exit;
     
      FCapacity    := 0;
      FCount       := 0;
      FElementSize := aElementSize;
      FMemStart    := nil;
     
      SetCapacity(aCapacity);
     
    end;
     
    procedure TBaseCtn.Free;
    begin
      if Assigned(FMemStart) then
      begin
        Clear;
        Freemem(FMemStart, FCapacity * FElementSize ); { On le libére de la mémoire }
        FCapacity := 0;                         { Maj capacité tableau }
        FMemStart := nil;                       { Affectation pointeur à VIDE}
      end;
    end;
     
    function TBaseCtn.Add(const Element): PtrUInt;
    begin
      //Result := 0;                      { Initie le resultat à 0 }
      //if FCount = FMemCapacity then Expand;{ Si liste pleine alors augmente taille liste }
     
      Move(Element, (FMemStart+(FCount * FElementSize))^, FElementSize);{ Copie Element dans le tableau de valeurs }
      Inc(FCount);                      { Incrémente le compteur de 1 position }
      //asm
      //  MOV EAX, FCount;     // Copie la valeur de Fcount à l'accumulateur AEX
      //  ADD EAX, 1           // Incrémente l'accumulateur de 1
      //  MOV FCount, EAX      // Copie la valeur de l'accumulateur dans la variable FCount
      //end;
     
      result := FCount;                 { Retourne la position du pointeur }
    end;
     
    procedure TBaseCtn.Insert(aIndex: PtrUInt; const aElement);
    begin
     
    end;
     
    function TBaseCtn.Clear : Boolean;
    begin
      if not Assigned(FMemStart) then Exit;
      try
        Result := False;
        FillChar(FMemStart, FCapacity * FElementSize, 0); { Initie à vide les blocs du tableau }
      finally
        FCount    := 0;                         { Maj nb éléments }
        Result    := True;
      end;
    end;
     
    function TBaseCtn.Delete(aIndex: PtrUInt) : Boolean;
    begin
      try
        result := False;
     	  FillByte((FMemStart + (aIndex * FElementSize))^, FElementSize, $00);  { Similaire à ZeroMemory de Delphi }
    	finally
        Dec(FCount);
        Result := True;
      end;
    end;
    Voici un exemple d'utilisation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    procedure TMainForm.BtBaseCtn(Sender: TObject);
    type
      TPerson = record
        age       : Integer;
        FirstName : string;
      end;
    var
      liste     : TBaseCtn;
      aPerson : TPerson;
      loop      : Integer;
    begin
      // * Initier la liste
      liste.Init(5, SizeOf(TPerson));
     
      { Test 1 : Ajout et parcours }
      ShowMessage( 'Test 3 : Clear + Lecture aléatoire '+RC
                   +IntToStr(TPerson(liste.Items[3]^).age));
     
     
      // * Ajouter des élémenents "FORME 1"
      aPerson.age:=12;
      for loop := 0 to liste.Capacity -1 do
      begin
        inc(aPerson.age);
        liste.Add(aPerson);     // Forme 1
      end;
     
      //Parcourir la liste
      for loop := 0 to liste.Capacity -1 do
      begin
        ShowMessage( 'Test 1 : Lecture en boucle'+RC
                     +IntToStr(TPerson(liste.Items[loop]^).age));
      end;
     
      // Test 2 : Lecture alétoire
      ShowMessage( 'Test 2 : Lecture aléatoire '+RC
                   +IntToStr(TPerson(liste.Items[3]^).age));
     
      // Test 3 : Nettoyer la liste et relecture aléatoire
      liste.Clear;
      ShowMessage( 'Test 3 : Clear + Lecture aléatoire '+RC
                   +IntToStr(TPerson(liste.Items[3]^).age));
     
      // Test 4 : Réinitier la liste et ajout d' éléments "FORME 2"
      liste.Capacity:=3;
     
      aPerson.age:=120;
      for loop := 0 to liste.Capacity -1 do
      begin
        inc(aPerson.age);
        liste.Items[loop] := Addr(aPerson); // Forme 2
      end;
     
      for loop := 0 to liste.Capacity -1 do
      begin
        ShowMessage( 'Test 4 : Reinit liste & lecture en boucle'+RC
                     +IntToStr(TPerson(liste.Items[loop]^).age));
      end;
     
      // Test 5 : Libérer la liste
      liste.Free;
    end;
    Tout commentaire sur le nommage, structure, organisation et amélioration du code du composant est le bienvenu.

    Merci beaucoup.

    Salim.

  2. #2
    Rédacteur/Modérateur
    Avatar de M.Dlb
    Inscrit en
    avril 2002
    Messages
    2 455
    Détails du profil
    Informations personnelles :
    Âge : 36

    Informations forums :
    Inscription : avril 2002
    Messages : 2 455
    Points : 4 246
    Points
    4 246
    Par défaut
    Bonjour,

    Ton objet TBaseCtn contient pas mal de pointeurs, donc pour proprement nettoyer, il faut aussi désallouer tous les pointeurs. Ta procédure Clear doit donc faire des dispose/freemem sur tous les éléments de l'objet. De la même façon, ta procédure Delete est un peu brutale, es-tu sûr de maîtriser entièrement ce code ?
    M.Dlb - Modérateur z/OS - Rédacteur et Modérateur Pascal

  3. #3
    Membre du Club
    Homme Profil pro
    Inscrit en
    février 2009
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations forums :
    Inscription : février 2009
    Messages : 34
    Points : 55
    Points
    55
    Par défaut
    Bonjour,

    L'objet contient un pointeur principal qui est FMemStart que j'alloue et désalloue avec GetMem (procedure TBaseCtn.SetCapacity) et FreeMem (procedure TBaseCtn.Free). La mémoire allouée (FMemStart) me sert de stockage de plusieurs éléments ayant tous une taille unique.

    Mon code fonctionne à ma satisfaction pour la création, ajout d'éléments et de destruction de l'objet. Mais je bute lors ce que je souhaite supprimer un seul élément stocké de la mémoire et lorsque je souhaite effacer la mémoire de tous les éléments qui y sont tout en ne désallouant pas la mémoire.

    Les fonctions qui posent problème sont les fonctions Clear et Delete car elle provoquent des erreurs à l'exécution.

    Merci.
    Salim.

  4. #4
    Rédacteur/Modérateur
    Avatar de M.Dlb
    Inscrit en
    avril 2002
    Messages
    2 455
    Détails du profil
    Informations personnelles :
    Âge : 36

    Informations forums :
    Inscription : avril 2002
    Messages : 2 455
    Points : 4 246
    Points
    4 246
    Par défaut
    Hello,

    Maintenant que j'ai compris le fonctionnement de FMemStart, c'est plus clair, et j'aurais fait exactement le même code que toi, pour la fonction Delete (pas regardé la fonction Clear).
    Comme je n'ai pas Lazarus, je ne pourrai pas tester ton code...

    Quelle est l'erreur que tu obtiens ?
    M.Dlb - Modérateur z/OS - Rédacteur et Modérateur Pascal

  5. #5
    Membre du Club
    Homme Profil pro
    Inscrit en
    février 2009
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations forums :
    Inscription : février 2009
    Messages : 34
    Points : 55
    Points
    55
    Par défaut
    Bonjour,
    Merci pour le temps consacré à mon problème.

    Dans l'exemple d'utilisation, j'initie d'abord l'objet (TBaseCtn.Init qui alloue la mémoire) puis accède directement à un élément indexé pour tester la valeur stockée qui doit être nulle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       liste.Init(5, SizeOf(TPerson));  // Initie la liste en allouant la mémoire
    { Test 0 : Accès élément nul }
    ShowMessage( 'Test 0 : Accès élément nul '+RC
                   +IntToStr(TPerson(liste.Items[3]^).age));
    La résultat retourné est : "-1", ce qui est logique ou à la limite acceptable.

    Mais une fois que je vide la liste avec TBaseCtn.Clear ou supprime un élément avecTBaseCtn.Delete, je teste à nouveau la valeur stockée qui me retourne dans les 2 cas une DialogBox avec "External: SIGSEGV" puis retour vers l'EDI et une nouvelle DialogBox avec "RunError(216)" et "Access Vioaltion".

    Sur internet, j'ai trouvé ceci :
    "216 General Protection fault
    The application tried to access invalid memory space. This can be caused by several problems:
    Dereferencing a nil pointer.
    Trying to access memory which is out of bounds (for example, calling move with an invalid length)."

    Si je comprends, j'essaie d’accéder à un bloc mémoire qui est hors limite, or les fonction TBaseCtn.Clear et TBaseCtn.Delete ne font que vider les blocs mémoire et non pas les désallouer. Sous Delphi, des forums conseillent l'usage de la fonction ZeroMemory, mais je n'ai pas Delphi pour tester. (lien : http://stackoverflow.com/questions/5...f-simple-types)

    J’espère avoir été clair et pas trop embrouillé.

    Salut.
    Salim.

    NB : Je tourne sous linux 3.0.2.68-1 / Debian 7 / FPC2.6 / Lazarus 1.5-SVN49892

  6. #6
    Membre chevronné

    Homme Profil pro
    au repos
    Inscrit en
    février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : février 2014
    Messages : 429
    Points : 1 884
    Points
    1 884
    Par défaut
    Bonjour.

    J'ai testé ton code sous Windows.
    Pas de problème avec Delete, mais Clear provoque l'erreur "External: SIGSEGV".

    Dans la procedure Clear, en déférençant FMemStart, cela parait ok :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FillChar(FMemStart^, FCapacity * FElementSize, 0);
    Cordialement
    Thierry

  7. #7
    Membre du Club
    Homme Profil pro
    Inscrit en
    février 2009
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations forums :
    Inscription : février 2009
    Messages : 34
    Points : 55
    Points
    55
    Par défaut
    Bonjour Thierry,
    Merci pour ton intervention. Effectivement le déférencement de la variable FMemStart a résolu mon souci sur la fonction Clear (un oubli idiot de ma part). Pour la fonction Delete, j'ai procédé aux modifications suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function TBaseCtn.Delete(aIndex: PtrUInt) : Boolean;
    var
      NextIndex : PtrUInt;
    begin
      try
        result := False;
        NextIndex := aIndex;
        inc(NextIndex);
        Move( (FMemStart+(NextIndex*FElementSize))^,   // Position élément index suivant
              (FMemStart+(aIndex*FElementSize))^,      // Position élément à supprimer
              (FCapacity-NextIndex)*FElementSize);     // taille depuis élément suivant à fin tableau
      finally
        Dec(FCount);
        Result := True;
      end;
    end;
    Cette modification me permet de remplacer le bloc à supprimer et de rendre disponible le dernier élément du tableau en mémoire.

    Merci à tous. Salutations.
    Salim.

  8. #8
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    mars 2005
    Messages
    3 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : mars 2005
    Messages : 3 632
    Points : 10 413
    Points
    10 413
    Billets dans le blog
    6
    Par défaut
    Juste une remarque en passant : le curseur risque d'être faussé, en cas de suppression d'un élément...
    Delphi 5 Pro - Delphi 10.3.2 Rio Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  9. #9
    Membre du Club
    Homme Profil pro
    Inscrit en
    février 2009
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations forums :
    Inscription : février 2009
    Messages : 34
    Points : 55
    Points
    55
    Par défaut
    Bonjour,
    Désolé pour la réponse tardive. J'ai testé la fonction Delete du composant TFPObjectList. Le comportement normal est bien la modification de l'index via un décalage négatif : l'index 3 devient index 2, etc.... comme cela a été fait dans ma modification du post précédent.

    Merci encore pour vos remarques.
    Salutations.
    Salim.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Copie de blocs mémoires
    Par Dmnbp7ip dans le forum C++
    Réponses: 2
    Dernier message: 18/12/2007, 12h58
  2. Bloc mémoire maximum allouable avec new
    Par uriotcea dans le forum C++Builder
    Réponses: 1
    Dernier message: 28/02/2007, 19h50
  3. Copier une bloc mémoire dans un CDC
    Par kinhelios dans le forum MFC
    Réponses: 3
    Dernier message: 23/02/2007, 10h17
  4. Réponses: 2
    Dernier message: 19/02/2007, 16h46
  5. Partage de blocs mémoire entre 2 processus
    Par rolkA dans le forum Windows
    Réponses: 6
    Dernier message: 18/11/2003, 20h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo