Domanda

Ci sono validi motivi di prestazioni da scegliere il collegamento statico sopra il collegamento dinamico o viceversa in determinate situazioni? Ho sentito o letto quanto segue, ma io non ne so abbastanza sull'argomento per garantire per la sua veridicità.

1) La differenza di prestazioni tra runtime collegamento statico ed linking dinamico è generalmente trascurabile.

2) (1) non è vero se si utilizza un compilatore profiling che utilizza i dati del profilo per ottimizzare hotpaths programma perché con collegamento statico, il compilatore può ottimizzare sia il codice e il codice della libreria. Con il collegamento dinamico solo il codice può essere ottimizzato. Se la maggior parte del tempo viene speso in esecuzione codice della libreria, questo può fare una grande differenza. In caso contrario, (1) si applica ancora.

È stato utile?

Soluzione

  • dinamica che collega possono ridurre il consumo totale di risorse (se le azioni più di un processo la stessa libreria (tra cui la versione "lo stesso", naturalmente)). Credo che questo sia l'argomento che spinge la sua presenza nella maggior parte degli ambienti. Qui "risorse" include lo spazio su disco, RAM e spazio della cache. Naturalmente, se il linker dinamico è sufficientemente flessibile, c'è il rischio di DLL hell .
  • dinamica di collegamento significa che le correzioni di bug e aggiornamenti alle librerie propagano per migliorare la tuo prodotto senza che sia necessario spedire nulla.
  • Plugin chiamare sempre per dinamica che collega.
  • Static che collega, significa che è possibile conoscere il codice verrà eseguito in molto ambienti limitati (nelle prime fasi del processo di avvio, o in modalità di ripristino).
  • Static che collega può fare binari più facile da distribuire per ambienti utente diversi (al costo di invio di un programma che utilizza molta più risorse e più grande).
  • Static di collegamento può permettere un po ' avvio più veloce di volte, ma questo dipende in una certa misura sia la dimensione e la complessità del programma di e su i dettagli della strategia di caricamento del sistema operativo.

Alcune modifiche per includere i suggerimenti molto rilevanti nei commenti e in altre risposte. Vorrei sottolineare che il modo in cui si interrompe su questo dipende molto da quale ambiente si prevede di eseguire in. Sistemi embedded minimi potrebbero non avere risorse sufficienti per supportare il collegamento dinamico. Un po 'piccoli sistemi più grandi possono ben supportano il collegamento dinamico, perché la loro memoria è abbastanza piccolo per fare il risparmio RAM da dinamiche che legano molto interessante. Pieno PC soffiato di consumo hanno, come Mark nota, enormi risorse, e probabilmente si può lasciare che i problemi di convenienza guidare il vostro pensiero su questo argomento.


Per affrontare i problemi di prestazioni e di efficienza: Dipende

.

Classicamente, librerie dinamiche richiedono un qualche tipo di strato di colla che spesso significa doppia spedizione o di un ulteriore livello di indirezione in funzione di indirizzamento e può costare un po 'di velocità (ma è la funzione di chiamata tempo effettivamente una grande parte del vostro tempo di esecuzione ?? ?).

Tuttavia, se si esegue più processi, che tutti chiamano la stessa libreria molto, si può finire per linee di cache risparmio (e quindi vincente su esecuzione delle prestazioni) quando si utilizza il collegamento dinamico rispetto al utilizzando il collegamento statico. (A meno che OS moderni sono abbastanza intelligenti da notare segmenti identici a binari linkati staticamente. Sembra difficile, qualcuno sa?)

Un altro problema: il tempo di caricamento. Si paga di caricare i costi a un certo punto. Quando si paga questo costo dipende da come il sistema operativo funziona così come quello che il collegamento si utilizza. Forse si preferisce rimandare il pagamento fino a quando si sa ne avete bisogno.

Si noti che il collegamento statico-vs-dinamica è tradizionalmente non un problema di ottimizzazione, perché entrambi coinvolgono compilazione separata fino al file oggetto. Tuttavia, questo non è richiesto: un compilatore può in linea di principio, il collegamento "Li con l'aggiunta di quelle AST a quelli generati per il codice principale, che abilita quindi l'ottimizzazione globale "compilazione" "librerie statiche" per una forma AST digerita inizialmente, e". Nessuno dei sistemi che uso fare questo, quindi non posso commentare su come funziona.

Il modo di rispondere alle domande di prestazioni è sempre testando (e utilizzare un ambiente di test tanto come l'ambiente di distribuzione il più possibile).

Altri suggerimenti

1) si basa sul fatto che chiamare una funzione DLL viene sempre usando un salto in più indiretta. Oggi, questo è di solito trascurabile. All'interno della DLL v'è ancora un po 'sovraccarico su CPU i386, perché non in grado di generare il codice posizione indipendente. Su amd64, salti possono essere relativi al contatore di programma, quindi questo è un enorme miglioramento.

2) Questo è corretto. Con ottimizzazioni guidate da profilatura di solito si può vincere circa il 10-15 per cento delle prestazioni. Ora che la velocità della CPU ha raggiunto i suoi limiti forse vale la pena di farlo.

Aggiungerei: (3) il linker può organizzare funzioni in una cache raggruppamento più efficiente, in modo che esce livello costoso cache vengono minimizzati. Potrebbe anche soprattutto effettuare il tempo di avvio delle applicazioni (in base ai risultati che ho visto con il Sole compilatore C ++)

E non dimenticare che senza l'eliminazione del codice morto DLL può essere eseguita. A seconda della lingua, il codice DLL potrebbe non essere ottimale sia. funzioni virtuali sono sempre virtuale perché il compilatore non sa se un client è sovrascriverlo.

Per queste ragioni, nel caso in cui non v'è alcun reale bisogno di DLL, quindi basta usare la compilazione statica.

EDIT (per rispondere al commento, da parte di sottolineatura utente)

Qui è una buona risorsa per la posizione problema di codice indipendente http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

Come spiegato x86 non li hanno per quanto ne so per niente altro poi gamme di salto 15 bit e non per i salti incondizionati e le chiamate. Ecco perché funzioni (da generatori) con più di 32K sono sempre stati un problema e trampolini incorporati necessari.

Ma sul popolare sistema operativo come Linux x86 proprio non c'è bisogno di preoccuparsi se il file / DLL SO non viene generata con l'interruttore gcc -fpic (che impone l'uso delle tabelle di salto indiretti). Perché se non lo fai, il codice è solo fissata come un linker normale avrebbe riposizionarla. Ma mentre si fa questo rende il segmento di codice non condivisibili e avrebbe bisogno di una mappatura completa del codice dal disco in memoria e toccando il tutto prima di poter essere utilizzato (svuotamento maggior parte delle cache, colpendo di TLB), ecc C'è stato un tempo quando questo è stato considerato lento ... troppo lento.

Quindi, non avrebbe più alcun beneficio.

Non ricordo quale sistema operativo (Solaris o FreeBSD) mi ha dato problemi con il mio sistema di compilazione Unix perché ho appena non stava facendo questo e mi chiedevo perché si è arrestato fino a quando ho fatto domanda per -fPIC gcc.

Il collegamento dinamico è l'unico modo pratico per soddisfare alcuni requisiti di licenza, come il LGPL .

Sono d'accordo con i punti dnmckee cita, oltre a:

  • applicazioni staticamente collegate potrebbe essere più facile da implementare, dato che ci sono meno o no dipendenze fra i file aggiuntivi (DLL / .so) che potrebbero causare problemi quando sono mancanti o installati nel posto sbagliato.

Una ragione per fare una build collegata in modo statico è quello di verificare di avere la completa chiusura per l'eseguibile, vale a dire che tutti i riferimenti dei simboli sono risolti correttamente.

Come parte di un grande sistema che veniva costruito e testato con l'integrazione continua, i test di regressione notturne sono stati eseguiti utilizzando una versione collegata in modo statico dei file eseguibili. Di tanto in tanto, vedremmo che un simbolo non risolverebbe ed il collegamento statico fallirebbe anche se l'eseguibile collegato dinamicamente collegherebbe con successo.

Questa è stata di solito si verificano quando i simboli che sono stati radicata all'interno delle librerie condivise avevano un nome misspelt e quindi non sarebbe collegare in modo statico. Il linker dinamico non risolve completamente tutti i simboli, a prescindere di utilizzare in profondità o ampiezza di valutazione, in modo da poter finire con un eseguibile collegato dinamicamente che non dispone di chiusura completa.

1 / Sono stato su progetti in cui il linking dinamico vs collegamento statico è stato benchmark e la differenza non è stato determinato abbastanza piccolo da passare a collegamento dinamico (non ero parte del test, so solo alla conclusione)

2 / dinamico di collegamento è spesso associato con PIC (Position Independent codice, il codice che non ha bisogno di essere modificato a seconda l'indirizzo al quale viene caricato). In base all'architettura PIC può portare un altro rallentamento, ma è necessaria al fine di ottenere il beneficio di condividere una libreria di collegamento dinamico tra due eseguibili (e anche di due processi dello stesso eseguibile se l'uso del sistema operativo randomizzazione di indirizzo di caricamento come misura di sicurezza). Non sono sicuro che tutti i sistema operativo permettono di separare i due concetti, ma Solaris e Linux fanno e ISTR che HP-UX fa pure.

3 / Sono stato su altri progetti che hanno usato il collegamento dinamico per la funzione "Easy patch". Ma questo "semplice patch" rende la distribuzione di piccola correzione un po 'più facile e di un complicato un incubo delle versioni. Spesso finito per dover spingere tutto più dover tenere traccia dei problemi presso il cliente, perché la versione sbagliata era token.

La mia conclusione è che avevo linking statico utilizzato escluso:

  • per cose come i plugin che dipendono linking dinamico

  • quando la condivisione è importante (grandi librerie usate da più processi allo stesso tempo come il C / C ++ di runtime, librerie GUI, ... che spesso sono gestite in modo indipendente e per i quali l'ABI è strettamente definita)

Se si desidera utilizzare il "semplice patch", direi che le librerie devono essere gestiti come le grandi librerie di cui sopra:. Devono essere quasi indipendente con un ABI definito che non deve essere cambiato correzioni

Questo discutere con dovizia di particolari sulle librerie condivise su Linux e prestazioni implicazioni.

E 'abbastanza semplice, in realtà. Quando si apporta una modifica nel codice sorgente, vuoi aspettare 10 minuti per costruire o 20 secondi? Venti secondi è tutto quello che posso sopportare. Oltre a ciò, io o uscire la spada o cominciare a pensare a come posso usare compilazione separata e il collegamento per riportarlo nella zona di comfort.

Sui sistemi Unix-like, il collegamento dinamico può rendere la vita difficile per i 'root' di utilizzare un'applicazione con le librerie condivise installate in luoghi out-of-the-way. Questo perché il linker dinamico in genere non presterà attenzione LD_LIBRARY_PATH o il suo equivalente per i processi con privilegi di root. A volte, poi, il collegamento statico salva la giornata.

In alternativa, il processo di installazione deve individuare le librerie, ma che può rendere difficile per più versioni del software per coesistere sulla macchina.

Il collegamento dinamico richiede più tempo per il sistema operativo di trovare la libreria dinamica e caricarlo. Con il collegamento statico, tutto è insieme ed è un carico di one-shot in memoria.

Inoltre, vedere inferno DLL . Questo è lo scenario in cui la DLL che i carichi del sistema operativo non è quello che è venuto con l'applicazione, o la versione che l'applicazione si aspetta.

Il miglior esempio per il linking dinamico è, quando la biblioteca dipende dall'hardware utilizzato. Nei tempi antichi la libreria matematica C è deciso di essere dinamici, in modo che ogni piattaforma può utilizzare tutte le funzionalità del processore ottimizzarlo.

Un esempio ancora migliore potrebbe essere OpenGL. OpenGL è un'API che viene implementata in modo diverso da AMD e NVidia. E non si è in grado di utilizzare un'implementazione NVidia su una scheda AMD, perché l'hardware è diverso. Non è possibile collegare OpenGL in modo statico nel vostro programma, a causa di questo. il collegamento dinamico è qui utilizzato per consentire l'API essere ottimizzato per tutte le piattaforme.

Un altro problema non ancora discussi è correggere i bug nella libreria.

Con il collegamento statico, non resta che ricostruire la biblioteca, ma sarà necessario ricollegare e redestribute l'eseguibile. Se la libreria è solo utilizzato in un unico eseguibile, questo potrebbe non essere un problema. Ma i più eseguibili che devono essere ricollegati e ridistribuito, più grande il dolore è.

Con collegamento dinamico, basta ricostruire e ridistribuire la libreria dinamica e si è fatto.

collegamento statico ti dà solo un singolo exe, inorder per fare un cambiamento è necessario ricompilare tutto il vostro programma. Mentre nel dinamico collegamento è necessario apportare modifiche solo alla DLL e quando si esegue l'exe, i cambiamenti sarebbero stati prelevati a runtime.Its più facile per fornire aggiornamenti e correzioni di bug per il collegamento dinamico. (Es: finestre)

Ci sono una serie vasta e crescente di sistemi in cui un livello estremo di collegamento statico può avere un enorme impatto positivo sulle applicazioni e le prestazioni del sistema.

mi riferisco a quelli che vengono spesso chiamati "sistemi embedded", molti dei quali sono ora sempre più utilizzano i sistemi operativi general-purpose, e questi sistemi sono utilizzati per tutto l'immaginabile.

Un esempio molto comune sono i dispositivi che utilizzano i sistemi GNU / Linux utilizzando Busybox . Ho preso questo all'estremo NetBSD costruendo un i386 avviabile sistema (32 bit) con quella comprende sia un kernel ed il filesystem principale, quest'ultimo contenente un singolo binario statico-linked (da crunchgen) con hard-collegamenti a tutti i programmi che si contiene tutti (bene ultimo conteggio 274) della programmi di sistema full-feature di serie (la maggior parte tranne la toolchain), ed è a meno di 20 mega byte di dimensione (e, probabilmente, corre molto comodamente in un sistema con solo 64 MB di memoria (anche con il filesystem root compresso e interamente in RAM), anche se sono stato in grado di trovare uno così piccolo per testarlo su).

E 'stato accennato nel post precedenti che il tempo di avvio di un binari statici-linked è più veloce (e può essere un molto più veloce), ma che è solo una parte del quadro, soprattutto quando tutto il codice oggetto è collegato nello stesso file, e ancora di più soprattutto quando il sistema operativo supporta demand paging del codice direttamente dal file eseguibile. In questo scenario ideale il tempo di avvio dei programmi è letteralmente trascurabile dal momento che quasi tutte le pagine del codice sarà già in memoria ed essere utilizzata dalla shell (e e init eventuali altri processi in background che potrebbero essere in esecuzione) , anche se il programma richiesto non è mai stato eseguito dall'avvio poiché forse solo una pagina di memoria deve essere caricata per soddisfare i requisiti di esecuzione del programma.

Tuttavia questo non è ancora tutta la storia. Ho anche di solito costruire e utilizzare il sistema operativo NetBSD installa per i miei sistemi di sviluppo pieno di Static-linking tutti i binari. Anche se questo richiede un enorme quantità di spazio su disco (~ totale 6.6GB per x86_64 con tutto, compreso toolchain e X11 statico-linked) (in particolare se si tiene tabelle dei simboli piena di debug disponibili per tutti i programmi di un altro ~ 2.5GB), il risultato ancora corre più veloce in generale, e per alcuni compiti ancora utilizza meno memoria di un sistema dinamico-linked tipico che pretende di condividere pagine code Library. Il disco è a buon mercato (anche disco veloce), e la memoria per memorizzare nella cache i file su disco utilizzati di frequente è anche relativamente a buon mercato, ma cicli di CPU in realtà non lo sono, e pagando il costo di avvio ld.so per ogni processo che inizia tutti tempo inizia avranno ore e ore di cicli di CPU distanti compiti che richiedono partendo molti processi, specialmente quando gli stessi programmi vengono utilizzati ripetutamente, come compilatori su un sistema di sviluppo. programmi toolchain statici-linked possono ridurre multi-architettura tempi di costruzione dell'intero sistema operativo per i miei sistemi, ore . Devo ancora costruire la toolchain nel mio singolo binario crunchgen'ed, ma ho il sospetto, quando io non ci sarò più ore di tempo di costruzione risparmiato a causa della vittoria per la cache della CPU.

linking statico include i file che il programma ha bisogno in un unico file eseguibile.

Il collegamento dinamico è quello che si prenderebbe in considerazione il solito, si fa un eseguibile che richiede ancora DLL e tali da essere nella stessa directory (o le DLL potrebbe essere nella cartella di sistema).

(DLL = collegamento dinamico library)

eseguibili collegate dinamicamente vengono compilati più veloce e non sono così risorsa-pesante.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top