Taille mémoire d'un tableau dynamique de string

Résolu
ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 - 1 mai 2009 à 19:28
ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 - 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 }

12 réponses

f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
2 mai 2009 à 01:01
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;

3
ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 12
3 mai 2009 à 06:56
@ 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 }
3
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
1 mai 2009 à 22:27
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 !
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
1 mai 2009 à 22:29
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 !
0

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

Posez votre question
ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 12
1 mai 2009 à 22:59
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 }
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
1 mai 2009 à 23:15
Aaaah !
Désolé désolé j'avais pas du tout capté ^^
Je réfléchis et je reposte :p

Cordialement, Bacterius !
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
1 mai 2009 à 23:17
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 !
0
ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 12
1 mai 2009 à 23:59
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 }
0
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
2 mai 2009 à 00:14
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;

0
ni69 Messages postés 1418 Date d'inscription samedi 12 juin 2004 Statut Membre Dernière intervention 5 juillet 2010 12
2 mai 2009 à 00:38
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 }
0
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
2 mai 2009 à 00:39
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;

0
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
2 mai 2009 à 21:45
hey salut ni69, ya un moment qu'on t'a pas vu, me trompe-je? :)
Comment va ?
0
Rejoignez-nous