ni69
Messages postés1418Date d'inscriptionsamedi 12 juin 2004StatutMembreDernière intervention 5 juillet 2010
-
1 mai 2009 à 19:28
ni69
Messages postés1418Date d'inscriptionsamedi 12 juin 2004StatutMembreDerniè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...
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202235 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;
ni69
Messages postés1418Date d'inscriptionsamedi 12 juin 2004StatutMembreDernière intervention 5 juillet 201012 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...!
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 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.
ni69
Messages postés1418Date d'inscriptionsamedi 12 juin 2004StatutMembreDernière intervention 5 juillet 201012 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!
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 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 ?
ni69
Messages postés1418Date d'inscriptionsamedi 12 juin 2004StatutMembreDernière intervention 5 juillet 201012 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!
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202235 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;
ni69
Messages postés1418Date d'inscriptionsamedi 12 juin 2004StatutMembreDernière intervention 5 juillet 201012 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.
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202235 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;