Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Taille de la pile

17 réponses
Avatar
roger_that
Bonjour,

Je me pose des questions par rapport à la taille de la pile qu'on peut
définir dans son compilateur (VC6 dans mon cas). Si j'ai bien compris,
la taille qu'on spécifie dans les options du projet (ou par l'options
/STACK ou par le programme Editbin) est une taille maximale utilisable
pour la pile. Cela garantit au démarrage une réservation de l'espace
d'adressage.
Au fur et à mesure de l'exécution du programme, lorsque celui-ci accède
à de nouvelles pages de la pile, le système alloue effectivement ces
pages. C'est ce que j'ai vu avec mon debugger (les "???" de la mémoire
inaccessible se transforment en mémoire accessible lorsque le programme
écrit dedans). Et d'autre part, la consommation mémoire du processus
augmente avec l'accès en écriture dans la pile.

Il est bien plus rapide d'"allouer" des buffers locaux sur la pile que
sur le tas, donc on a intéret à maximiser la taille dispo pour la pile.
Bon, pour un x86 on risque d'être limité par l'étroitesse de l'espace
d'adressage, mais sur les AMD-64, j'imagine qu'on peut voir large (par
exemple allouer 4Go d'adressage pour la pile).

Partagez-vous mon analyse ?
Merci de votre attention.

7 réponses

1 2
Avatar
En Espadrilles
Le Mon, 19 Apr 2004 22:01:39 +0200, Arnaud Debaene a écrit :

Enfin, si tu fais du C++, la différence fondamentale entre la pile et le
tas n'est pas une question de vitesse d'allocation mais de sémantique de
durée de vie des objets : un objet sur la pile est détruit uand il sort
du "scope", pas sur le tas.



C'est bien pour ça que j'ai parlé de buffers locaux (c'est mon cas).
Quand il n'y a pas de problème de performance, je ne m'amuse pas à
écrire des choses cryptiques.
Après, rien n'empêche d'encapsuler ça dans une classe.
Avatar
Vincent Burel
"Arnaud Debaene" wrote in message
news:4084351a$0$21158$
Vincent Burel wrote:
>>
>> celle de VC, celle de Borland ou autre... Tu penses à laquelle en
>> particulier?
>
> générallement le malloc utilise un HeapAlloc ou un GlobalAlloc...
> Après il est évident qu'un programmeur sait quand est-ce qu'il faut
> utiliser ces fonctions ou pas :-)
Les CRT rajoutent leur propre mécanisme de cache/allocation par blocs par
dessus HeapAlloc, donc les problématiques de fragmentation/espace contigu
disponible/vitesse des allocations sontt complêtement différentes quand on
utilise une CRT.



oui, mais rien n'empêche d'utiliser du malloc (sur de gros espace) pour
gérer une collection de petit objet... ainsi c'est toi qui controle la
fragmentation de ta mémoire... Après tout dépend de l'utilisation que l'on
va faire, je ne suis pas fan de l'objet super généraliste (ca prend trop de
temps à définir, et généralement ca marche pas ), mais plutot de l'objet qui
répond au besoin.

Par exemple prenons le cas du stream comme objet de sauvegarde de contexte
d'une collection d'objet divers, si l'on doit sauver le contexte souvent, et
que la collection est grande, il vaut mieux se faire un objet Stream sur
mémoire non libérée (mémoire grossissante - éventuellement avec gestion
d'une limite : par exemple 1 Mega) d'abord ca va beaucoup plus vite que les
stream C++ de merde, en plus on alloc pas souvent parce qu'on alloc la
mémoire par page de 64Ko par exemple, et on free jamais (sauf en fin de prog
bien sur).

> Si la taille des élément reste petite (de 1 octet à quelque kilo) on
> peut faire des gestion particulière sur un tas qui augment par pas de
> 500 kilo ou 5 Mega et qui autorise une défragmentation en mode
> Idle... mais ca c'est un truc de programmeur évidemment :-)



Tu penses à un garbage collector ou à autre chose?



Non je, pense à mes librairies, que j'ai programmé quand j'étais petit et
qui me servent encore ... :-)


>>> Et c'est sans parler des techniques d'optimisation (buffer pool :
>>> allouer de la mémoire par avance et réutiliser les buffers...)
>> Bien sûr, c'est juste beaucoup de boulot en plus.
>
> ben, une fois que c'est fait, c'est fait,
Non : il faut le faire à chaque programme.



ha bon ! ? bizarre ca ! :-) on a au moins droit au Copié / Collé (la
combinaison de touche préférée des pro ! les autres sont obligés de vraiment
programmer de nouvelles lignes de code, ce doit être affreux ! :-)

> et étant donné que ca fait
> partie des premieres choses qu'on développe quand on commence
> l'informatique : tableau dynamique, gestion de collection d'objet,
> gestion mémoire, gestion de fichier, database, tri , dichotomie...
> bon je vais pas vous faire le programme de première année de BTS...
> mais bon, si ta pas ces outils dans ta musette , change de métier.
Tu es toujours aussi désagréable à chaque fois que tu réponds, oh grand
gourou de l'informatique?



De temps en temps, je lance une petite pique de provocation, histoire de
repérer les nouveaux ! :-) et à chaque fois c'est toi qui sort du bois ! :-)
je crois que je vais arréter ! :-)

>>> Tu es limité par la taille de la mémoire virtuelle avant celle de
>>> l'es- pace d'adressage. Je rappelle que les processus sous windows
>>> s'exécutent tous dans un segment virtuel de 4Go. En gros si le tas
>>> peut pas faire 4Go, la pile le pourra pas plus.
>
> 1 Go pour le mapping DLL et un autre pour le mapping system... il
> reste même pas 1Go pour le code je crois
Tu crois mal : Il y a 2GO pour *toutes* les données du mode user : code,
tas, piles, TLS, données statiques, etc...



non je crois bien, "croire" c'est quand on est pas sûr et qu'on peut se
tromper car on a pas la Doc Microsoft sous les yeux. :-)

> ,et la pile (par thread )
> est par défaut de l'ordre de qqc Mega...
Comme l'OP la dit, c'est (généralement) un paramètre du compilateur. C'est
en tout cas un champ dans l'en-tête des fichiers PE (SizeOfStackReserve et
StackOfSizeCommit dans IMAGE_OPTIONAL_HEADER). La valeur par défaut est


1MO.

voila 1 Mo ! étant donné cette valeur par défaut , on peut peut être penser
qu'il vaut mieux ne pas trop pousser l'engin (tiens , je ne sais pas si la
pile est virtualisable ... )...

VB
Avatar
adebaene
Cyrille Szymanski wrote in message news:<40843dc9$0$6863$...
On 2004-04-19, Arnaud Debaene wrote:
>> Le gros problème sous Windows c'est les implémentations foireuses
>> de malloc() &co., du genre :
> Ce n'est pas Windows qui implémente malloc : c'est la CRT que tu utilises :

Où vois-tu que j'ai dit le contraire ?


Nul part, c'était juste pour être sûr qu'on parle de la même chose :-)


> celle de VC, celle de Borland ou autre... Tu penses à laquelle en
> particulier?

Oui : celles de Borland et de lcc-win32. Pour VC je n'ai pas testé.


>> * pour allouer un bloc il faut généralement traverser tous ceux
>> du tas avant de trouver un espace libre, ce qui est cata-
>> strophique au niveau performance.
> Tu connais des implémentations d'allocateur généraliste (pas de taille fixe,
> etc...) qui font autrement sans obtenir rapidement une fragmentation
> catastrophique?

Oui : celle de la lib C que j'ai sous FreeBSD par exemple.
http://www.freebsd.org/cgi/man.cgi?query=malloc&apropos=0&sektion=0&manpath=FreeBSD+5.2-RELEASE+and+Ports&format=html



Intéressant, mais ils ne disent pas grand chose :
The major difference between this implementation and other
allocation
implementations is that the free pages are not accessed unless
allocated,
and are aggressively returned to the kernel for reuse.

Most allocation implementations will store a data structure con-
taining a linked list in the free chunks of memory, used to tie
all
the free memory together. That can be suboptimal, as every time
the free-list is traversed, the otherwise unused, and likely paged
out, pages are faulted into primary memory. On systems which are
paging, this can result in a factor of five increase in the number
of page-faults done by a process.

Si je comprend bien, ca veut dire que la CRT ne maintient pas de "free
blocks list" et que c'est le kernel qui fait lui-même ce travail. Ca
signifie que :

- à chaque appel de malloc, il y a un passage en mode noyau. Je ne
sais pas pour FreeBSD, mais généralement un passage en mode noyau
c'est assez lourd.

- comment est ce que le kernel fait, lui, pour trouver un espace
disponible dans l'espace d'adressage du processus? J'ai beau me
creuser la tête, je ne vois pas d'autre moyens qu'une recherche
linéaire, soit dans une table des blocs alloués/libres (il y a
peut-être moyen d'optimiser en triant cette table - par taille de
blocs peut-être? - mais ce tri n'est lui même pas gratuit), soit dans
une liste chainée des blocs.
Générallement, les algos sont d'ailleurs nettement plus compliqué pour
minimoser la fragmentation. Tu as des détails sur la méthode utilisée
par le memory manager de FreeBSD?

Je rajoute une remarque : en parcourant toute la liste chaînée des
blocs on tue tous les effets bénéfiques de la pagination.


Exact.

Après on s'étonne qu'un appel à malloc soit gourmand et on cherche
à bidouiller une autre solution qui généralement rend les programmes
moins stables.


Si, et uniquement si, ca pose un réel problème de perfs.


Dire "c'est normal que ça plante tu as appelé free() avec un mauvais
paramètre, c'est écrit dans la doc il n'y a rien à changer" quand on
sait le nombre de bogues que cela engendre moi j'appelle ça de la
mauvaise foi.


Ce que je veux dire, c'est que ca relève de la qualité
d'implémentation, mais que le comportement est conforme à la norme.

Ceci-dit, quand on utilise malloc/free si on a l'idiome RAII à sa
disposition, c'est qu'on tend le baton pour se faire battre ;-) (ce
n'est pas *toujours* vrai, mais quand même pour la majorité des
allocations faites générallement dans un programme C).


>> Rien qu'en changeant de routine malloc() &co. on y gagne.
> Et en la remplacant par?

Une autre implémentation de malloc(), il en existe même certaines
capables de faire du gc.


Oui, mais tu changes complètement la logique de ton programme dans ce
cas là.

Ou alors en dernier recours, ta propre
implémentation.


Le problème, c'est que les allocateurs fournis dans les CRT doivent
être généralistes, c'est à dire qu'ils doivent se comporter
"raisonnablement" bien pour tous les schémas d'allocation. Ca signifie
bien sûr qu'ils sont sous-optimaux dans des schémas d'allocation
particuliers. Si c'est vraiment nécessaire, on peut alors
effectivement les remplacer.

Je ne vais pas citer ESR, cela a déjà été fait dans ce fil, mais
il ne faut pas se lancer tête baissée dans des optimisations
aléatoires.


Amen!

Arnaud
Avatar
adebaene
"AMcD®" wrote in message news:<40843d89$0$17627$...
Arnaud Debaene wrote:

> Tu crois mal : Il y a 2GO pour *toutes* les données du mode user :
> code, tas, piles, TLS, données statiques, etc...

Toi aussi tu crois mal, cela dépend de ton OS et de quelques réglages :o).
Par exemple, via le célèbre /3GB, tu peux avoir 3GO d'espace d'adressage.



Tout à fait : ce que je voulais dire, c'est que Windows n'impose pas
une taille limite d'un côté pour le code, de l'autre pour les tas,
etc... Il te donne un "paquet" de mémoire, et tu débrouilles avec !

Arnaud
Avatar
Vincent Burel
"Cyrille Szymanski" wrote in message
news:408440fe$0$15693$
> ben, une fois que c'est fait, c'est fait, et étant donné que ca fait


partie
> des premieres choses qu'on développe quand on commence l'informatique :
> tableau dynamique, gestion de collection d'objet, gestion mémoire,


gestion
> de fichier, database, tri , dichotomie... bon je vais pas vous faire le
> programme de première année de BTS... mais bon, si ta pas ces outils


dans ta
> musette , change de métier.

Beaucoup de programmeurs "hobbyistes" n'ont malheureusement pas ça
dans leur musette et quand ils les ont (par ex ils ont pris la peine
de lire des bouts de la STL) ils les utilisent n'importe comment.



c'est vrai j'oubliais, autant on peu faire comprendre à un mécanicien qu'il
faut des outils pour travailler, autant avec un informaticien , c'est pas
évident :-). Et autant tu peux montrer à un mécanicien comment on utilise
tel ou tel outil, autant l'informaticient est persuadé qu'il peut utiliser
l'outil sans apprendre à le manier :-) Bref... on l'a vu, programmeur, avant
d'être un métier, c'est un état d'esprit ! :-)

> Maintenant alloué de la mémoire dans la pile, à part pour quelque kilo


de
> variables locales... ca ne se pratique pas des masses...

J'ai un avis mitigé sur la question.

C'est vrai qu'une allocation sur la pile est plus rapide que sur le
tas, alors pour les variables locales, même si elles sont grandes,
ça vaut le coup.



Et pour cause , le principe de la pile c'est d'avoir une mémoire déjà alloué
! :-)

VB
Avatar
Cyrille Szymanski
On 2004-04-20, Arnaud Debaene wrote:
Intéressant, mais ils ne disent pas grand chose :



Tu peux regarder le code source si tu as 5min à perdre :

http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdlib/malloc.c?rev=1.87&content-type=text/x-cvsweb-markup

Je ne vais pas défendre cette implémentation (il y a par exemple
une horreur ligne 696-698) mais elle est moins foireuse que celles
que j'ai utilisé auparavent.

J'ai entré "free malloc c implementation" dans goole et je suis tombé
sur pas mal de pages intéressantes, dont celle de Doug Lea.


Si je comprend bien, ca veut dire que la CRT ne maintient pas de "free
blocks list" et que c'est le kernel qui fait lui-même ce travail.



Si, cette info est contenue dans les listes chaînées pginfo et pgfree.
La différence est que ces métadonnées sont contenues dans des pages
contigues et non éparpillées un peu partout dans la mémoire.


- à chaque appel de malloc, il y a un passage en mode noyau. Je ne
sais pas pour FreeBSD, mais généralement un passage en mode noyau
c'est assez lourd.



Il n'y a d'appel au noyau que pour obtenir de nouvelles pages, donc
pour un fonctionnement "générique" où la mémoire se vide et se remplit
régulièrement c'est assez rare.


Générallement, les algos sont d'ailleurs nettement plus compliqué pour
minimoser la fragmentation. Tu as des détails sur la méthode utilisée
par le memory manager de FreeBSD?



C'est fait avec la méthode des "buckets" (dont tu as une description
sur la page de Doug Lea) mais je suppose que la plupart des malloc()
l'utilise aussi.


Ceci-dit, quand on utilise malloc/free si on a l'idiome RAII à sa
disposition, c'est qu'on tend le baton pour se faire battre ;-) (ce
n'est pas *toujours* vrai, mais quand même pour la majorité des
allocations faites générallement dans un programme C).



C'est clair.


Une autre implémentation de malloc(), il en existe même certaines
capables de faire du gc.


Oui, mais tu changes complètement la logique de ton programme dans ce
cas là.



Je voulais juste dire que ça fait pas de mal de rappeler qu'on peut
remplacer presque toutes les briques avec lesquelles on construit son
programme. Et si c'est lent, c'est pas forcément de sa faute.

--
cns
Avatar
Arnaud Debaene
Cyrille Szymanski wrote:
On 2004-04-20, Arnaud Debaene wrote:
Intéressant, mais ils ne disent pas grand chose :



Tu peux regarder le code source si tu as 5min à perdre :




http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdlib/malloc.c?rev=1.87&content-type=text/x-cvsweb-markup

Je ne vais pas défendre cette implémentation (il y a par exemple
une horreur ligne 696-698) mais elle est moins foireuse que celles
que j'ai utilisé auparavent.

J'ai entré "free malloc c implementation" dans goole et je suis tombé
sur pas mal de pages intéressantes, dont celle de Doug Lea.


Si je comprend bien, ca veut dire que la CRT ne maintient pas de
"free
blocks list" et que c'est le kernel qui fait lui-même ce travail.



Si, cette info est contenue dans les listes chaînées pginfo et pgfree.
La différence est que ces métadonnées sont contenues dans des pages
contigues et non éparpillées un peu partout dans la mémoire.



Ok, je vois. Cette solution est effectivement plus rapide (rapport au
paging) mais elle est par contre plus gourmande en espace mémoire : il faut
maintenir une liste séparée des blocs libres (ou des blocs occupés...), et
cette liste prend en elle-même de la place. La solution "classique" ou les
noeuds de la liste chainée sont dans les espaces disponibles eux-même ne
demande pas d'espace mémoire supplémentaire.

Arnaud
1 2