494 votes

Liaison statique et liaison dynamique

Existe-t-il des raisons impérieuses, en termes de performances, de préférer la liaison statique à la liaison dynamique ou vice-versa dans certaines situations ? J'ai entendu ou lu ce qui suit, mais je n'en sais pas assez sur le sujet pour en garantir la véracité.

1) La différence de performance à l'exécution entre la liaison statique et la liaison dynamique est généralement négligeable.

2) (1) n'est pas vrai si vous utilisez un compilateur de profilage qui utilise les données de profil pour optimiser les hotpaths du programme, car avec la liaison statique, le compilateur peut optimiser à la fois votre code et celui de la bibliothèque. Avec la liaison dynamique, seul votre code peut être optimisé. Si la majeure partie du temps est consacrée à l'exécution du code de la bibliothèque, cela peut faire une grande différence. Sinon, le point (1) reste valable.

78 votes

"Avec la liaison statique, le compilateur peut optimiser le code de la bibliothèque", mais seulement s'il la compile aussi ! Si vous vous contentez de lier des fichiers objets précompilés, votre compilateur n'a pas la possibilité de les optimiser.

3 votes

Si c'est vrai, alors vous avez raison, mais on peut se demander dans quelle mesure cela est vrai avec les compilateurs modernes. Si quelqu'un peut le vérifier d'une manière ou d'une autre, ce serait formidable.

5 votes

Avec un compilateur qui compile en code natif (comme la plupart des compilateurs C/C++), il n'y a plus de possibilité d'optimisation du code. Si le code est compilé dans un langage intermédiaire (comme .Net IL), le compilateur JIT est invoqué lorsque la bibliothèque est chargée pour la compiler en code natif. Cette compilation finale peut s'améliorer de plus en plus avec le temps, au fur et à mesure que le compilateur JIT évolue.

424voto

dmckee Points 50318
  • Dynamique la liaison peut réduire la consommation totale de ressources (si plus d'un processus partage la même bibliothèque (y compris la version dans "le même", bien sûr)). Je crois que c'est l'argument qui lui vaut sa présence dans la plupart des environnements. Ici, les "ressources" comprennent l'espace disque, la RAM et l'espace de cache. Bien entendu, si votre éditeur de liens dynamiques n'est pas suffisamment flexible, il y a un risque de L'enfer des DLL .
  • Dynamique La liaison signifie que les corrections de bogues et les mises à jour des bibliothèques propager pour améliorer votre sans que vous ayez à expédier quoi que ce soit.
  • Plugins toujours demander dynamique liaison.
  • Statique de liaison, ce qui signifie que vous pouvez savoir que le code s'exécutera dans des délais très courts. environnements limités (au début du processus de démarrage, ou en mode de secours).
  • Statique l'enchaînement peut faire des binaires plus facile à distribuer à divers environnements d'utilisateurs (au prix de l'envoi d'un programme plus volumineux et plus gourmand en ressources).
  • Statique La liaison peut permettre une légère démarrage plus rapide temps, mais cela dépend dans une certaine mesure de la taille et de la complexité de votre programme. et sur les détails de la stratégie de chargement de l'OS.

Quelques modifications pour inclure les suggestions très pertinentes dans les commentaires et dans d'autres réponses. J'aimerais noter que la façon dont vous vous y prenez dépend beaucoup de l'environnement dans lequel vous prévoyez de fonctionner. Les systèmes embarqués minimaux peuvent ne pas avoir assez de ressources pour supporter la liaison dynamique. Les petits systèmes un peu plus grands peuvent très bien prendre en charge la liaison dynamique, car leur mémoire est suffisamment petite pour que les économies de RAM réalisées grâce à la liaison dynamique soient très intéressantes. Les PC grand public ont, comme Mark le note, des ressources énormes, et vous pouvez probablement laisser les questions de commodité guider votre réflexion sur ce sujet.


Pour résoudre les problèmes de performance et d'efficacité : cela dépend .

Classiquement, les bibliothèques dynamiques nécessitent une sorte de couche de collage, ce qui signifie souvent une double répartition ou une couche supplémentaire d'indirection dans l'adressage des fonctions et peut coûter un peu de vitesse (mais le temps d'appel des fonctions est-il vraiment une partie importante de votre temps d'exécution ???).

Cependant, si vous exécutez plusieurs processus qui font souvent appel à la même bibliothèque, vous pouvez finir par économiser des lignes de cache (et donc gagner en performances d'exécution) en utilisant la liaison dynamique par rapport à la liaison statique. (A moins que les systèmes d'exploitation modernes soient assez intelligents pour remarquer les segments identiques dans les binaires liés statiquement. Cela semble difficile, quelqu'un le sait).

Autre problème : le temps de chargement. Vous payez des frais de chargement à un moment donné. Le moment où vous payez ce coût dépend du fonctionnement du système d'exploitation ainsi que de la liaison que vous utilisez. Peut-être préférez-vous reporter ce paiement jusqu'à ce que vous sachiez que vous en avez besoin.

Notez que la liaison statique-vs-dynamique est traditionnellement pas un problème d'optimisation, car ils impliquent tous deux une compilation séparée jusqu'aux fichiers objets. Cependant, cela n'est pas nécessaire : un compilateur peut en principe "compiler" des "bibliothèques statiques" sous une forme AST digérée au départ, et les "lier" en ajoutant ces AST à ceux générés pour le code principal, ce qui permet une optimisation globale. Aucun des systèmes que j'utilise ne le fait, je ne peux donc pas me prononcer sur son efficacité.

La façon de répondre aux questions de performance est la suivante toujours par des tests (et utilisez un environnement de test ressemblant le plus possible à l'environnement de déploiement).

32 votes

La consommation de ressources correspond essentiellement à l'espace de code, ce qui, au fil du temps, est de moins en moins préoccupant. Si 500K de bibliothèque sont partagés entre 5 processus, cela représente une économie de 2MB, soit moins de 0,1% de 3GB de RAM.

4 votes

Si la bibliothèque partage également le même mappage virtuel (la même adresse physique et virtuelle dans tous les processus), une liaison dynamique n'économise-t-elle pas également des emplacements TLB dans la MMU du processeur ?

11 votes

De plus, un lien dynamique facilite la mise à jour d'un code de bibliothèque bogué par de meilleures versions.

78voto

Lothar Points 4740

1) est basé sur le fait que l'appel d'une fonction DLL utilise toujours un saut indirect supplémentaire. Aujourd'hui, cela est généralement négligeable. À l'intérieur de la DLL, il y a un peu plus de surcharge sur les CPU i386, car ils ne peuvent pas générer de code indépendant de la position. Sur amd64, les sauts peuvent être relatifs au compteur du programme, ce qui constitue une amélioration considérable.

2) C'est correct. Avec des optimisations guidées par le profilage, vous pouvez généralement gagner environ 10 à 15 % de performance. Maintenant que la vitesse du CPU a atteint ses limites, cela peut valoir la peine de le faire.

J'ajouterais : (3) l'éditeur de liens peut arranger les fonctions dans un groupement plus efficace pour le cache, de sorte que les coûteux manques au niveau du cache soient minimisés. Cela pourrait aussi avoir un effet particulier sur le temps de démarrage des applications (d'après les résultats que j'ai vus avec le compilateur C++ de Sun).

Et n'oubliez pas qu'avec les DLL, il n'est pas possible d'éliminer les codes morts. Selon le langage, le code de la DLL peut ne pas être optimal non plus. Les fonctions virtuelles sont toujours virtuelles car le compilateur ne sait pas si un client les écrase.

Pour ces raisons, s'il n'y a pas de réel besoin de DLL, il suffit d'utiliser la compilation statique.

EDIT (pour répondre au commentaire, par le soulignement de l'utilisateur)

Voici une bonne ressource sur le problème du code indépendant de la position http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

Comme expliqué, le x86 ne les a pas AFAIK pour autre chose que les plages de saut de 15 bits et pas pour les sauts et les appels inconditionnels. C'est pourquoi les fonctions (des générateurs) ayant plus de 32K ont toujours été un problème et ont nécessité des trampolines intégrés.

Mais sur les systèmes d'exploitation x86 courants comme Linux, vous n'avez pas besoin de vous soucier du fait que le fichier .so/DLL n'est pas généré avec la commande gcc commutateur -fpic (qui impose l'utilisation des tables de saut indirect). Parce que si vous ne le faites pas, le code est juste fixé comme un linker normal le relocaliserait. Mais en faisant cela, cela rend le segment de code non partageable et il faudrait un mappage complet du code du disque vers la mémoire et le toucher avant de pouvoir l'utiliser (vider la plupart des caches, frapper les TLB), etc. Il fut un temps où cela était considéré comme lent.

Vous n'auriez donc plus aucun avantage.

Je ne me souviens pas quel système d'exploitation (Solaris ou FreeBSD) m'a posé des problèmes avec mon système de construction Unix, car je ne le faisais pas et je me demandais pourquoi il plantait jusqu'à ce que j'applique la méthode suivante -fPIC à gcc .

6 votes

J'aime cette réponse, car c'est la seule qui aborde les points que j'ai soulevés dans la question.

0 votes

Il serait intéressant d'avoir des références sur les aspects techniques de ces DLL, et une comparaison entre les différents systèmes d'exploitation.

1 votes

Tout semble aller bien, mais la vitesse du processeur n'a certainement pas atteint ses limites.

72voto

Mark Ransom Points 132545

L'établissement de liens dynamiques est le seul moyen pratique de répondre à certaines exigences de licence, comme la norme LGPL .

19 votes

Tant que l'utilisateur final peut établir un lien vers le code LGPL (par exemple, parce que vous fournissez votre code source ou des fichiers objets compilés avec votre logiciel), alors la liaison statique est parfaite . En outre, si votre logiciel est destiné à un usage interne (c'est-à-dire à être utilisé au sein de votre organisation uniquement, et non distribué), vous pouvez établir une liaison statique. Cela s'applique par exemple à un logiciel de serveur, lorsque le serveur n'est pas distribué.

3 votes

Ne l'obtenez pas. Pourriez-vous me donner plus de sources (ou élaborer davantage) afin d'apprécier ce que vous avez écrit ?

5 votes

@Thorn voir le Licence LGPL section 4.d+e . Vous devez soit distribuer sous une forme qui oblige l'utilisateur à faire un lien, soit distribuer une bibliothèque partagée (dynamique).

47voto

stakx Points 29832

Je suis d'accord avec les points que dnmckee mentionne, en plus :

  • Les applications liées statiquement peuvent être plus faciles à déployer, car il y a moins ou pas de dépendances de fichiers supplémentaires (.dll / .so) qui peuvent causer des problèmes lorsqu'ils sont manquants ou installés au mauvais endroit.

8 votes

Il est intéressant de noter que le compilateur Go de Google va seulement compilent statiquement les binaires pour cette raison principalement.

35voto

Rob Wells Points 21714

L'une des raisons d'effectuer une compilation avec liaison statique est de vérifier que vous disposez d'une fermeture complète pour l'exécutable, c'est-à-dire que toutes les références aux symboles sont correctement résolues.

Dans le cadre d'un grand système qui était construit et testé à l'aide de l'intégration continue, les tests de régression nocturnes étaient exécutés à l'aide d'une version liée statiquement des exécutables. Il arrivait parfois qu'un symbole ne soit pas résolu et que la liaison statique échoue, même si l'exécutable lié dynamiquement se liait avec succès.

Cela se produisait généralement lorsque des symboles profondément ancrés dans les librairies partagées avaient un nom mal orthographié et ne pouvaient donc pas être liés statiquement. L'éditeur de liens dynamiques ne résout pas complètement tous les symboles, qu'il utilise l'évaluation en profondeur ou en largeur, et vous pouvez donc vous retrouver avec un exécutable lié dynamiquement qui n'a pas une fermeture complète.

1 votes

Très bon point, j'ai essayé de faire cela récemment avec un code que j'ai au travail, mais tout compiler de manière statique s'est avéré étonnamment ennuyeux et j'ai abandonné.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X