OVH Cloud OVH Cloud

Utilité DLL C++

100 réponses
Avatar
Korchkidu
Bonjour,

A partir de quand estimez vous que faire une DLL plutot qu'un LIB soit
int=E9ressant. En effet, utiliser des DLL fait des programmes plus
petits (entre autres) mais induit d'enormes contraintes au niveau de la
programmation. Donc d'apres moi, faire une DLL pour une bibliotheque de
petite taille n'est pas forcement une bonne idee...

Merci pour vos commentaires.
K=2E

10 réponses

1 2 3 4 5
Avatar
Vincent Burel
"Alain Gaillard" wrote in message
news:45013aa5$0$25908$
Le mécanisme de gestion de mémoire virtuelle est assez particulier. En
quelques mots disons que toute application se voit attribuer les 4 Go
adressables, mais toute cette zone est une zone de mémoire virtuelle,
pas physique évidemment. Les 2 go de mémoire basse sont à son usage.
Dans les 2 Go de mémoire haute sont installée les tables de saut vers
les dll utilisées par l'application, comme par exemple kernel32.dll,
user32.dll, madll.dll. Je parle bien ici de mémoire virtuelle.

Quand une appli appelle une fonction de dll, elle saute quelque part
dans ces deux Go de mémoire haute puis de là saute dans la mémoire
*physique* où est effectivement chargée la dll. Et cette dll ne réside
qu'une fois en mémoire physique.



Pour un process donné oui... Pour deux process utilisant la meme DLL, je ne
suis pas certain que cette DLL ne soit pas physiquement chargé 2 fois...

VB
Avatar
Jean-Claude BELLAMY
Dans le message :450142a2$0$27367$,
Vincent Burel a pris la peine d'écrire ce
qui suit :
"Alain Gaillard" wrote in message
[...]
Quand une appli appelle une fonction de dll, elle saute quelque part
dans ces deux Go de mémoire haute puis de là saute dans la mémoire
*physique* où est effectivement chargée la dll. Et cette dll ne
réside qu'une fois en mémoire physique.



Pour un process donné oui... Pour deux process utilisant la meme DLL,
je ne suis pas certain que cette DLL ne soit pas physiquement chargé
2 fois...



Exact !!!

Ce qui retire d'ailleurs pas mal d'intérêt aux DLL en ce qui concerne
l'encombrement mémoire.
Cela date du monde 16 bits, la "mono-résidence" en mémoire de DLL.
Le passage en 32 bits a modifié cette gestion.

--
May the Force be with You!
La Connaissance s'accroît quand on la partage
----------------------------------------------------------
Jean-Claude BELLAMY [MVP]
http://www.bellamyjc.org ou http://jc.bellamy.free.fr
Avatar
Alain Gaillard
Jean-Claude BELLAMY a écrit :


Exact !!!



FAUX!!!


Ce qui retire d'ailleurs pas mal d'intérêt aux DLL en ce qui concerne
l'encombrement mémoire.




Regardez par exemple les dépendances du Notepad. Il utilise
Kernel32.dll, gdi32.dll, user32.dll, comctl32.dll, shell32.dll,
msvcrt.dll, pour ne citer que ça et tout son processus n'occupe que 600k
environ. Si toutes ces dll étaient chargées en mémoire au lancement du
notepad, ça ferait beaucoup plus.

Vous imaginez un peu le notepad chargeant le noyau de windows ??
(kernel32.dll) Une application qui chargeait le noyau de son OS c'est
quand même le monde à l'envers. Assez psychédélique ;-) :-)

La MSDN est tout à fait claire au sujet des dll:

"DLLs provide a way to modularize applications so that functionality can
be updated and reused more easily. They also help reduce memory overhead
when several applications use the same functionality at the same time,
because although each application gets its own copy of the data, they
can share the code"

> Cela date du monde 16 bits, la "mono-résidence" en mémoire de DLL.
> Le passage en 32 bits a modifié cette gestion.

Dans tes rêves...

--
Alain
Avatar
Vincent Burel
"Alain Gaillard" wrote in message
news:450156cb$0$5106$
Jean-Claude BELLAMY a écrit :

"DLLs provide a way to modularize applications so that functionality can
be updated and reused more easily. They also help reduce memory overhead
when several applications use the same functionality at the same time,
because although each application gets its own copy of the data, they
can share the code"



Ha ouai, chaque process à ses donnée propres de ses DLL, ca devrait suffire
effectivement...
Avatar
Arnold McDonald \(AMcD\)
Jean-Claude BELLAMY wrote:

Exact !!!

Ce qui retire d'ailleurs pas mal d'intérêt aux DLL en ce qui concerne
l'encombrement mémoire.



N'importe quoi...

Prends un debugguer et scrute quelques applis. Ne confond pas chargé et
mappé, ne confonds pas en mémoire et sur disque. Et ne confond pas données
et code...

Eh ! Les vacances sont finies, faut se reconcentrer man :-).

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
Jean-Claude BELLAMY
Dans le message :45017658$0$6978$,
Arnold McDonald (AMcD) a pris la peine d'écrire ce
qui suit :
Jean-Claude BELLAMY wrote:


Une conceté !
[...]
Prends un debugguer et scrute quelques applis. Ne confond pas chargé
et mappé, ne confonds pas en mémoire et sur disque. Et ne confond pas
données et code...

Eh ! Les vacances sont finies, faut se reconcentrer man :-).



Justement, je n'ai pas encore pris de vacances ! (il faut je j'attende
dimanche 17)

Oui, j'ai répondu trop vite et j'ai dit une conceté !
(d'ailleurs au moment où j'ai posté j'avais un pressentiment!)
Mais je n'ai jamais confondu mémoire et sur disque, ni données et code,
quand même !

Je m'étais rappelé l'article du MSDN "How To Build and Service Isolated
Applications and Side-by-Side Assemblies for Windows XP", à propos des
applications "autonomes" sous cet OS. J'ai retrouvé l'URL :
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwxp/html/sidexsidewinxp.asp

Je venais par ailleurs de recompiler un contrôle ActiveX alors qu'il était
en cours d'utilisation par une autre appli, et tout çà sans aucune
injurebox, ce qui m'a évoqué cette phrase de l'article cité plus haut
(dans le paragraphe intitulé "Step two: Design and author DLLs so that
multiple DLLs may run safely"):
"DLLs need to be authored so that multiple versions can run
at the same time in a process without impacting each other"

Donc s'il peut y avoir simultanément plusieurs versions de la même DLL,
c'est que forcément ces versions occupent des emplacements mémoire
différents.
Si bien que j'ai extrapolé un peu trop rapidement et me suis mélangé les
octets...

Désolé ..


--
May the Force be with You!
La Connaissance s'accroît quand on la partage
----------------------------------------------------------
Jean-Claude BELLAMY [MVP]
http://www.bellamyjc.org ou http://jc.bellamy.free.fr
Avatar
kanze
Rémy wrote:
"kanze" a écrit dans le message de news:

Rémy wrote:



>> Nous utilisons des DLL (en fait des .so) pour les modules
>> communs d'applications composées de plusieurs (dizaines) de
>> processus. Ca n'apporte rien fonctionnellement par rapport
>> à l'édition de liens statique, mais ça économise
>> considérablement la mémoire car le code n'est présent
>> qu'une fois en mémoire.



> En es-tu certain ? Ce n'est pas ce que j'ai compris
> jusqu'ici, et ça ne correspond pas au nom. Au moins sous
> Windows : je sais que la taille était bien la motivation
> principale des « shared objects » sous Sun OS, dans le
> temps, mais je croyais qu'il s'agissait principalement de la
> taille sur disque (à une époque où la taille des disques se
> mesurait en Mo, et non Go, et que la taille de la
> bibliothèque graphique était bien plusieurs Mo).



Oui (en tout cas sur les OS sur lesquels je travaille
habituellement : Sun OS, HP-UX, Tru 64 et Linux.



En effet. J'ai jeté un coup d'oeil à l'assembleur généré pour
malloc, pour Linux, et ils ont fait ce qu'il faut pour que ça
marche. (Je n'ai pas vérifié en détail que les exécutables
partagent le code, mais générer l'assembleur comme ils l'ont
fait n'a pas de sens autrement.)

J'aurais cru qu'avec l'augmentation des tailles mémoire, qu'on
aurait préféré l'optimisation vitesse -- parce que l'interface
PIC qu'ils utilisent a bien un coup non negligeable en temps
d'exécution. Que tu paies à chaque appel de fonction, et non
seulement lors du chargement. (Pour une fonction simple
comme :
int
f()
{
static int i = 0 ;
return i ++ ;
}
le temps d'exécution pourrait prèsque doublé. L'effet quand la
fonction n'utilise pas de variables statiques, en revanche, est
bien moindre.)

> C'est possible que l'image en mémoire soit partagé ; c'est
> même l'idée derrière le PIC (« position independant code »,
> mais ça augmente aussi la vitesse de chargement de façon
> notable, même si l'image n'est pas partagé).



Oui, aussi.



> Mais ça suppose aussi que l'objet
> partagé ne réfère jamais à rien dans le main,



Effectivement, il vaut mieux que le .so ne réfère rien dans le main...



Et cependant, pour un plug-in, ça peut être intéressant.

Mais pour des composants communs, il vaut mieux ne pas
dépendre de l'utilisateur. Seulement d'autres composants
communs et encore, en évitant les dépendances circulaires...



> et que s'il réfère à quelque chose dans un autre objet
> partagé (libc, par exemple), que cet autre objet soit lié à
> la même adresse dans tous les exécutables (rélative à
> l'adresse de mon objet partagé, au moins).



Ma foi, je pense que c'est le boulot de l'édition de lien dynamique
d'assurer que ça marche.



Oui, mais à quel coût. Il y introduit un niveau d'indirection
supplémentaire à chaque appel. Voire deux. En fait, l'édition de
liens ne se fait que partiellement dans dlopen. Une bonne partie
se réfait, dynamiquement, à chaque appel.

Je ne sais pas s'il est nécessaire que les objets soient à la
même adresse dans tous les exécutables ?



>> Par ailleurs, ça permet de livrer les corrections des
>> modules communs sans que le programme les utilisant n'ait à
>> être relinké.



> C'est justement le gros problème. L'utilisateur finit très
> vite avec un melange de versions incompatibles.



Il y a un travail sérieux pour s'assurer de la compatibilité
ascendante. Il n'y a pas de "mélange" de version car (dans
notre cas) une nouvelle version remplace la précédente (les
composants communs sont installés une seule fois sur la
machine et pas avec chaque exécutable).



Je suppose que ton équipe est la seule qui s'en servent, et
qu'elle gère bien le code, et y a pensé. Dans notre cas, il y
plusieurs équipes, et la contrôle de ce qui va dans chaque
version est assez limitée.

C'est une contrainte supplémentaire sur l'évolution.

> Ici, ils avaient fait à peu près pareil, avec l'idée
> qu'effectivement, la plupart des bibliothèques servaient à
> plusieurs exécutables. Seulement, juste au moment où j'y
> suis arrivé, on a eu des crashs en production parce que
> $LD_LIBRARY_PATH ne désignait pas le chemin vers la bonne
> version de la bibliothèque



Problème effectivement si on installe plusieurs versions sur
la même machine



Disons qu'en général, si chaque exécutable est livrée avec tous
les objets partagés qui lui servent, il n'y a vraiment aucun
gain. Et dès qu'on ne prend pas en compte les problèmes de
compatibilité ascendante, c'est ce qu'il va falloir.

Ensuite, c'est une décision pragmatique qui s'impose. Si
l'utilisation des objets partagés fait réelement une différence
importante, que la contrainte de la compatibilité ascendante
ne pose pas de grands problèmes (ou qu'elle est présente de
toute façon, pour d'autres raisons), et que tu maîtrises un peu
les environements où vont tournés les exécutables, l'utilisation
des objets partagés peut se justifier.

> -- un peu de récherche a montré
> qu'en fait, les versions des exécutables (livrées par des
> équipes différentes) étaient telles que chaque exécutable avait
> besoin d'une version différente des bibliothèques.



Si chacun fait évoluer les composants communs de façon
incompatible... Eh bien, ils ne sont plus communs...



Le problème, c'est qu'on fasse évoluer une fonctionnement de
façon qu'il ne soit plus compatible avec l'ancienne version. Du
coup, les applications qui n'ont pas été modifiées ne
fonctionnent qu'avec les anciennes versions.

Il faut ajouter que les binaires des différentes versions du
compilateur ne sont pas compatible non plus, au moins en ce qui
concerne le C++. Selon les équipes, on utilise trois différentes
versions de Sun CC (dont la très ancienne 4.2), plus g++. Et
qu'il faudrait un objet partagé différent pour chaque version.

Je pense que ce n'est faisable qu'avec une organisation
adaptée. Dans notre cas, il y a une équipe chargée de toutes
les livraisons qui réceptionne les sources de tous les
produits (communs ou pas), recompile tout sur une machine
dédiée et génère les produits à installer.



C'est sûr qu'avec une bonne organisation, on a plus de chances à
ce que ça marche qu'avec une mauvaise:-).

> Les bibliothèques étaient donc présentes autant de fois
> qu'il y avait d'exécutables, dans de versions différentes.
> Pas de gain de place, donc, et une risque réele de chopper
> la mauvaise version.



C'est comme beaucoup d'outils, si on s'en sert mal (ou sans
les contrôler), on peut faire de gros dégâts ;-)



Tout à fait. Et chaque fois, il s'agit de comparer ce que ça
peut apporter par rapport aux prix que ça impose. Il y a
certainement des cas où le gain de place mémoire est à prendre
en compte.

Une question supplémentaire : est-ce que quelqu'un sache si ça
marche pareil sous Windows ? Je ne vois pas d'option pour
générer du PIC. Je doute donc que c'est possible, mais je ne
connais pas la plate-forme assez bien pour être sûr.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
kanze
Alain Gaillard wrote:
kanze a écrit :



> En es-tu certain ?



Il peut l'être sous Windows.



> Ce n'est pas ce que j'ai compris jusqu'ici, et ça ne
> correspond pas au nom. Au moins sous Windows



Mon bon James, tu manques un peu d'expérience dans le domaine
;) (pardonne moi mais je n'ai pas pu m'en empêcher:) )



Sous Windows les dll ne sont chargées qu'une fois en mémoire,
ce qui est heureux car sinon tout le système, qui est
constitué uniquement de dll serait chargé par chaque
application. kernel32.dll, user32.dll. Tu imagines ?



J'aurais imaginé que ces DLL ne contient que le mapping de l'API
C aux véritables appels systèmes (qui n'était pas des call dans
le temps, parce qu'il fallait passer en mode superuser, masquer
les interruptions, etc.). Mais de toute façon, le système
lui-même est un cas à part, parce qu'en aucun cas il ne faut le
mapper dans l'espace utilisateur.

Le mécanisme de gestion de mémoire virtuelle est assez
particulier. En quelques mots disons que toute application se
voit attribuer les 4 Go adressables, mais toute cette zone est
une zone de mémoire virtuelle, pas physique évidemment. Les 2
go de mémoire basse sont à son usage. Dans les 2 Go de
mémoire haute sont installée les tables de saut vers les dll
utilisées par l'application, comme par exemple kernel32.dll,
user32.dll, madll.dll. Je parle bien ici de mémoire virtuelle.



Il lui faut 2 Go pour ça ?

Quand une appli appelle une fonction de dll, elle saute
quelque part dans ces deux Go de mémoire haute puis de là
saute dans la mémoire *physique* où est effectivement chargée
la dll. Et cette dll ne réside qu'une fois en mémoire
physique.



Pour les sauts dans le code, je comprends bien comment ça
marche, bien que j'ai du mal à croire que tout le monde soit
d'accord pour le prix de l'indirection supplémentaire. Et pour
les sauts à l'intérieur d'une DLL, il n'y a évidemment aucun
problème, parce que les sauts sur un Intel (sauf pour les
adresses FAR, mais ni Windows ni Linux ne les supporte) sont
rélatifs. Le problème se pose, en revanche, dès qu'une fonction
ait des données statiques -- il faut tout un cirque pour s'y
accéder.

Je viens de vérifier et sous Linux et sous Solaris, et quand tu
donnes l'option -fpie (g++) ou -PIC (Sun CC), le compilateur
génère le code supplémentaire nécessaire. Ce qui va rallentir
considérablement une fonction très simple qui se sert d'une
variable statique, mais de telles fonctions ne font certainement
pas la majorité de beaucoup d'applications. (En revanche, ça
doit avoir un effet notable sur des fonctions dans <ctype.h>.)
Je ne trouve pas d'option pareil dans VC++ (mais j'avoue que je
n'ai fait que « cl /help » pour régarder -- et peut-être ils
l'ont appelé quelque chose d'autre, et que je ne reconnais pas
la description.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Arnold McDonald \(AMcD\)
Jean-Claude BELLAMY wrote:

Justement, je n'ai pas encore pris de vacances ! (il faut je j'attende
dimanche 17)



Patience, plus que 9 jours !

Oui, j'ai répondu trop vite et j'ai dit une conceté !
(d'ailleurs au moment où j'ai posté j'avais un pressentiment!)



T'inquiète, ça arrive à tout le monde. J'ai été simplement surpris de ta
part.

Mais je n'ai jamais confondu mémoire et sur disque, ni données et
code, quand même !



C'était une extrapolation. Je voulais signifier que les données étaient
dupliquées, pas le code. Pareil pour le mapping et le chargement (disque et
mémoire).

Si bien que j'ai extrapolé un peu trop rapidement et me suis mélangé
les octets...



Désolé ..



Pas de problème, la prochaine fois, ce sera toi qui me reprendra :-).

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
kanze
Alain Gaillard wrote:
Jean-Claude BELLAMY a écrit :



> Exact !!!



FAUX!!!



> Ce qui retire d'ailleurs pas mal d'intérêt aux DLL en ce qui
> concerne l'encombrement mémoire.



Regardez par exemple les dépendances du Notepad. Il utilise
Kernel32.dll, gdi32.dll, user32.dll, comctl32.dll,
shell32.dll, msvcrt.dll, pour ne citer que ça et tout son
processus n'occupe que 600k environ. Si toutes ces dll étaient
chargées en mémoire au lancement du notepad, ça ferait
beaucoup plus.



Je n'en suis pas si sûr. Chez moi (Windows NT), le Task Manager
montre environ 1 Mo pour Notepad, et Kernel32.dll n'est pas si
gros que ça. Et la taille du fichier Notepad.exe n'est que 50Ko.

Aussi, je ne sais pas exactement ce que comptabilise le Task
Manager. D'une part, c'est bien possible que tu aies raison,
mais que le Task Manager comptabilise le DLL pour chaque
processus quand même (parce qu'elle est bien mappée dans
l'espace d'adressage du processus). Ou inversemment, qu'il y a
certaines espaces qu'il ne comptabilise pas, bien qu'ils soient
propre à chaque processus.

Vous imaginez un peu le notepad chargeant le noyau de windows
?? (kernel32.dll) Une application qui chargeait le noyau de
son OS c'est quand même le monde à l'envers. Assez
psychédélique ;-) :-)



Aucun processus utilisateur n'a même directement accès au noyau.
Heureusement, d'ailleurs.

La MSDN est tout à fait claire au sujet des dll:



"DLLs provide a way to modularize applications so that
functionality can be updated and reused more easily. They also
help reduce memory overhead when several applications use the
same functionality at the same time, because although each
application gets its own copy of the data, they can share the
code"



Reste à savoir comment il s'arrange pour rétrouver ces données
sans imposer qu'il soit liées à la même adresse dans dans tous
les processus. Sous Unix, c'est simple. Tu passes une option
spéciale au compilateur, et le compilateur génère un tas d'extra
code pour calculer l'adresse dynamiquement, à partir d'une
adresse de rétour d'une fonction. Jusqu'ici, je n'ai pas trouvé
une option pareille dans VC++. Si je régarde le code généré pour
ma fonction simple, j'ai à peu près la même chose avec VC++
qu'avec g++ (sans -fpie) sous Linux. Si j'ajoute le -fpie sous
Linux, du coup, la fonction commence par un appel à une autre
fonction (__i686.get_pc_thunk.cx) et des bricolages sur
l'adresse, et accède à la variable avec un adressage basé sur un
règistre. Comment fait VC++ pour résoudre ce problème.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
1 2 3 4 5