Taille mémoire d'un tableau dynamique de string [Résolu]

ni69 1529 Messages postés samedi 12 juin 2004Date d'inscription 5 juillet 2010 Dernière intervention - 1 mai 2009 à 19:28 - Dernière réponse : ni69 1529 Messages postés samedi 12 juin 2004Date d'inscription 5 juillet 2010 Dernière intervention
- 3 mai 2009 à 06:56
Bonjour,

Est-il possible de connaître exactement la taille mémoire occupée par un tableau dynamique de string ?
J'ai cherché un bon moment sans rien trouver de concret...

var
paths: array of string;

Merci d'avance 
@+
Nico { www.ni69.info }
Afficher la suite 

12 réponses

Répondre au sujet
f0xi 4302 Messages postés samedi 16 octobre 2004Date d'inscriptionModérateurStatut 20 mars 2017 Dernière intervention - 2 mai 2009 à 01:01
+3
Utile
Decoupage d'un type String :

[P-12 : word 2 code page]
[P-10 : word 2 element size]
[P-8 : LongInt 4 Reference count]
[P-4 : LongInt 4 Length]
[P : char start]
[P+N : ZT]

quelques ptites fonctions qui le font bien :

type
  pStringRec = ^TStringRec;
  TStringRec = packed record
    CodePage: Word;
    ElemSize: Word;
    RefCnt: Longint;
    Length: Longint;
  end;
 
const
  SizeOfTStringRec = SizeOf(TStringRec);
 
function GetStringRec(S : string) : TStringRec;
begin
  result := pStringRec(integer(S)-SizeOfTStringRec)^;
end;

function GetStringMemorySize(S: string): int64;
var
  SR : TStringRec;
begin
  SR := pStringRec(integer(S)-SizeOfTStringRec)^;
  result := ((SR.length+1)*SR.elemSize)+SizeOfTStringRec+4;
end;

Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de f0xi
ni69 1529 Messages postés samedi 12 juin 2004Date d'inscription 5 juillet 2010 Dernière intervention - 3 mai 2009 à 06:56
+3
Utile
@ foxi :

Pour cela je suis d'accord:
4[RefCounter] + 4[Length] + SES[] + SES[] + ... + SES[] + SES[NULL]

Pour le tableau, c'est bon aussi:
4[RefCounter] + 4[Length] + 4[pointer_1] + 4[pointer_2] + ... + 4[pointer_n]

Mais la fonction nécessite deux petites adaptations, car d'une part en cas de chaîne vide on ne doit prendre en compte que l'espace d'un pointeur vide, et d'autre part l'allocation mémoire se fait par blocs de 4 octets:

function SizeOfStringArray(const A: array of string): int64;
var
  SES, I : integer;
begin
  SES := StringElementSize('a');
  result := 8 + 4*Length(A);
  for I := Low(A) to High(A) do
    if A[I]<>'' then result := result + 8 + (  (  (Length(A[I])*SES)  div  4) + 1 )*4;
end;

J'avais déjà bricolé un truc de ce genre là, mais je me demandais s'il n'existait pas une routine spéciale pour ce genre de calcul, car cette méthode, bien que fonctionnant effectivement en pratique, est un peu lourde à mon sens... (et puis aussi, je ne dispose pas de StringElementSize dans ma version de Delphi!)

@ Juliodelphi :
Ca va bien merci! C'est vrai que ça fait un petit moment que je ne suis pas repassé sur delphifr, mais il faut avouer que le temps me manque un peu en ce moment...!

@+
Nico { www.ni69.info }
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de ni69
Bacterius 3871 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 1 mai 2009 à 22:27
0
Utile
Oui c'est possible : c'est juste Length(TableauString) + 1 ^^ puisque chaque caractère est codé sur 1 octet, alors le nombre de caractères correspond à la taille du tableau, + 1 octet pour stocker je ne sais quelle information lol.

Cordialement, Bacterius !
Commenter la réponse de Bacterius
Bacterius 3871 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 1 mai 2009 à 22:29
0
Utile
En fait tu as sûrement déjà remarqué que l'élément TableauString[0] est inaccessible. C'est la raison pour laquelle on fait Length(TableauString) + 1.

Cordialement, Bacterius !
Commenter la réponse de Bacterius
ni69 1529 Messages postés samedi 12 juin 2004Date d'inscription 5 juillet 2010 Dernière intervention - 1 mai 2009 à 22:59
0
Utile
Bonsoir Bacterius,

"chaque caractère est codé sur 1 octet"
On n'y est pas du tout ! Il s'agit là d'un array of string, et non d'un array of char

Tout le problème réside justement en le fait que les string sont des pointeurs, et que pour touts: string, on a :
SizeOf(s) = 4
c'est à dire exactement la taille d'un pointeur (integer).

De plus si on déclare paths: array of string; alors
Length(paths)
renvoie le nombre d'éléments dans l'array, et aucunement la taille mémoire (en octets j'entends) du tableau!

@+
Nico { www.ni69.info }
Commenter la réponse de ni69
Bacterius 3871 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 1 mai 2009 à 23:15
0
Utile
Aaaah !
Désolé désolé j'avais pas du tout capté ^^
Je réfléchis et je reposte :p

Cordialement, Bacterius !
Commenter la réponse de Bacterius
Bacterius 3871 Messages postés samedi 22 décembre 2007Date d'inscription 3 juin 2016 Dernière intervention - 1 mai 2009 à 23:17
0
Utile
Hmm ...

type
TStringArray = array of String;

procedure SizeOfArray(Value: TStringArray): Longword;
Var
I: Integer;
begin
Result := 0;
for I := 0 to Length(Value) - 1 do
Inc(Result, Length(Value[I]));
end;

Ca ne marche pas ? Ici il parcourt tous les string de ton tableau, et vérifie leur longueur (nombre de caractères, donc taille en octets), puis on ajoute ça au résultat ?

Cordialement, Bacterius !
Commenter la réponse de Bacterius
ni69 1529 Messages postés samedi 12 juin 2004Date d'inscription 5 juillet 2010 Dernière intervention - 1 mai 2009 à 23:59
0
Utile
Le problème est bien plus complexe que celà...
J'ai regardé comment la mémoire était effectivement allouée à la déclaration des  array of string  grâce à  AllocMemSize.

Supposons que l'on parte de
paths: array of string;
paths := nil;

Lors de la première étape, c'est à dire
SetLength(paths,10);
le programme alloue 48 octets  = 8 (déclaration du tableau) + 10*4 (allocation de 10 pointeurs)
Jusque là rien de bien compliqué.

Mais supposons maintenant que nous entrions une chaîne non vide dans un des emplacements du tableau:
paths[2] := 'a';
le programme vient d'allouer 12 octets supplémentaires. Et cette valeur est la même que si l'on avait fait:
paths[2] := 'abc';
car l'allocation se fait par tranches de 4 octets (12 =8+4) !

Encore deux exemples :
paths[2] := 'abcd';  et  paths[2] := 'abcdefg';
nécessitent 16 octets de plus en mémoire que le tableau vide

Ayant tout cela en tête, le calcul de proche en proche peut être réalisable avec une boucle et quelques divisions entières par 4, mais cela me semble très long et fastidieux (mon tableau contient en pratique quelques centaines de milliers de chaînes, et je tiens à éviter de toutes les parcourir). D'autant que si l'on peut facilement récupérer la longueur d'une chaîne standard ( array of char ), cela devient plus compliqué quand un codage particulier est employé, qui peut varier d'une chaîne à l'autre!

@+
Nico { www.ni69.info }
Commenter la réponse de ni69
f0xi 4302 Messages postés samedi 16 octobre 2004Date d'inscriptionModérateurStatut 20 mars 2017 Dernière intervention - 2 mai 2009 à 00:14
0
Utile
function SizeOfStringArray(const TSA: array of string): Int64;
Var
  I,SESV,SES: Integer;
begin
  result := 0;
  SES    := 1;
  for I := Low(TSA) to High(TSA) do
  begin
    Result := Result +  Length(TSA[I]);

    SESV := StringElementSize(TSA[I]); 
    if SESV > SES then
      SES := SESV;
  end;
 
  Result := Result * SES;
end;

Commenter la réponse de f0xi
ni69 1529 Messages postés samedi 12 juin 2004Date d'inscription 5 juillet 2010 Dernière intervention - 2 mai 2009 à 00:38
0
Utile
Bonsoir foxi,

Je ne connaissais pas la fonction StringElementSize. Après recherche elle n'est disponible que dans Delphi2009.
Je m'imagine cependant assez bien ce qu'elle renvoie.

Par contre le code que tu as écrit ne donne pas du tout l'espace mémoire occupé pour la bonne raison qu'il ne prend pas en compte les chaînes vides du tableau qui occupent tout de même 4 octet chacunes en mémoire, ni les allocations par blocs telles que je les ai décrites dans mon message précédent.

Le problème principal restant qu'il est nécessaire de parcourir tout le tableau, chose que je voulais éviter.

@+
Nico { www.ni69.info }
Commenter la réponse de ni69
f0xi 4302 Messages postés samedi 16 octobre 2004Date d'inscriptionModérateurStatut 20 mars 2017 Dernière intervention - 2 mai 2009 à 00:39
0
Utile
ah oui tu veux la taille en memoire ....

mmm difficile, puisque delphi gere ça un peu comme bon lui semble.

le truc etant qu'on sait 2 choses :

String est toujours du même type selon le contexte ... il ne peu varier au cours d'un programme, il est donc soit codé sur 8 bytes (UTF8) ou 16 (UTF16) ...
on peu le savoir grace a StringElementSize

ensuite on sait que la taille d'un string est codé sur 4 octet (integer).
que cette chaine est AZT et dispose d'un pointeur au tout debut ...
soit :
[4][4]([n][1]*Char Size)

S = 8+((Length(S)+1) * StringElementSize(S))
 
maintenant que sait on des tableaux de chaine dynamique ?

Array[0..0] of string = Array[0..0] of pointer
soit

donc Array of string contenant 4 chaines =
[4][4][4*[4]]+[[4][4]([n][1]*Char Size)];

SAD = 8 + (Length(Tableau)*4);
for Low(Tableau) to High(Tableau) do
  SAD = SAD + (8+((Length(S)+1) * StringElementSize(S)))

soit

function SizeOfStringArray(const A : array of string) : int64;
var
  SES, I : integer;
begin
  SES := StringElementSize('A');
  result := 8 + (Length(A)* (12+(1*SES)));
  for I := Low(A) to High(A) do
    result := result + (Length(A[I])*SES);
end;

Commenter la réponse de f0xi
JulioDelphi 2354 Messages postés dimanche 5 octobre 2003Date d'inscriptionModérateurStatut 18 novembre 2010 Dernière intervention - 2 mai 2009 à 21:45
0
Utile
hey salut ni69, ya un moment qu'on t'a pas vu, me trompe-je? :)
Comment va ?
Commenter la réponse de JulioDelphi

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.