Pergunta

Há convincente desempenho razões para escolher a vinculação estática sobre a ligação dinâmica ou vice-versa, em determinadas situações?Eu ouviu ou leu o seguinte, mas eu não sei o suficiente sobre o assunto para atestar a sua veracidade.

1) A diferença no desempenho de tempo de execução entre a vinculação estática e dinâmica de vinculação é geralmente insignificante.

2) (1) não é verdade que se a utilizar um perfil do compilador que usa os dados do perfil para otimizar o programa hotpaths porque com a vinculação estática, o compilador pode otimizar o seu código e o código da biblioteca.Com a ligação dinâmica apenas o seu código pode ser otimizado.Se a maioria do tempo é gasto para executar a biblioteca de código, isso pode fazer uma grande diferença.Caso contrário, (1) ainda se aplica.

Foi útil?

Solução

  • Dinâmico Linking pode reduzir o consumo total de recursos (Se mais de um processo compartilha a mesma biblioteca (incluindo a versão em "a mesma", é claro)). Eu acredito que este é o argumento que impulsiona sua presença na maioria dos ambientes. Aqui "Recursos" incluem espaço em disco, RAM e espaço de cache. Obviamente, se o seu ligante dinâmico é insuficientemente flexível, existe um risco de Dll Inferno.
  • Dinâmico Vincular significa que correções de bugs e atualizações para bibliotecas propagar melhorar sua Produto sem exigir que você envie nada.
  • Plugins sempre ligue dinâmico vincular.
  • Estático Vincular, significa que você pode saber que o código será executado muito ambientes limitados (no início do processo de inicialização ou no modo de resgate).
  • Estático Vincular pode fazer binários mais fácil de distribuir para diversos ambientes de usuário (ao custo de enviar um programa maior e mais faminto de recursos).
  • Estático vincular pode permitir um pouco Startup mais rápido vezes, mas isso depende até certo ponto do tamanho e da complexidade do seu programa e sobre os detalhes da estratégia de carregamento do sistema operacional.

Algumas edições para incluir as sugestões muito relevantes nos comentários e em outras respostas. Gostaria de observar que a maneira como você quebra isso depende muito do ambiente que você planeja executar. Os sistemas incorporados mínimos podem não ter recursos suficientes para apoiar a ligação dinâmica. Sistemas pequenos ligeiramente maiores podem suportar a ligação dinâmica, porque sua memória é pequena o suficiente para tornar muito atraente a economia de RAM de vinculação dinâmica. Os PCs de consumo completos têm, como Notas Mark, recursos enormes, e você provavelmente pode deixar os problemas de conveniência impulsionarem seu pensamento sobre esse assunto.


Para abordar os problemas de desempenho e eficiência: depende.

Classicamente, as bibliotecas dinâmicas exigem algum tipo de camada de cola, que geralmente significa despacho duplo ou uma camada extra de indireção na abordagem de função e pode custar um pouco de velocidade (mas é o tempo de chamada de função na verdade uma grande parte do seu tempo de execução ???).

No entanto, se você estiver executando vários processos que todos chamam muito da mesma biblioteca, poderá acabar salvando linhas de cache (e assim vencendo o desempenho em execução) ao usar a ligação dinâmica em relação ao uso da ligação estática. (A menos que os sistemas operacionais modernos sejam inteligentes o suficiente para perceber segmentos idênticos em binários estaticamente vinculados. Parece difícil, alguém sabe?)

Outra questão: tempo de carregamento. Você paga custos de carregamento em algum momento. Quando você paga, esse custo depende de como o sistema operacional funciona, bem como o que você usa. Talvez você prefira adiar pagando até saber que precisa.

Observe que a ligação estática-vs-dinâmica é tradicionalmente não Um problema de otimização, porque ambos envolvem compilação separada até arquivos de objeto. No entanto, isso não é necessário: um compilador pode, em princípio, "compilar" "bibliotecas estáticas" a um formulário de AST digerido inicialmente e "vinculá -los" adicionando esses ASTs aos gerados para o código principal, capacitando assim a otimização global. Nenhum dos sistemas que eu uso faz isso, então não posso comentar sobre como ele funciona.

A maneira de responder a perguntas de desempenho é sempre testando (e use um ambiente de teste o mais parecido com o ambiente de implantação possível).

Outras dicas

1) baseia -se no fato de que chamar uma função DLL está sempre usando um salto indireto extra. Hoje, isso geralmente é insignificante. Dentro da DLL, há um pouco mais de sobrecarga nos CPUs i386, porque eles não podem gerar código independente de posição. No AMD64, os saltos podem ser relativos ao contador do programa, então isso é uma grande melhoria.

2) Isso está correto. Com otimizações guiadas pelo perfil, você geralmente pode ganhar cerca de 10 a 15 % de desempenho. Agora que a velocidade da CPU atingiu seus limites, pode valer a pena fazer isso.

Eu acrescentaria: (3) O vinculador pode organizar funções em um agrupamento mais eficiente em cache, para que as perdas caras de nível de cache sejam minimizadas. Também pode afetar especialmente o tempo de inicialização das aplicações (com base nos resultados que vi com o compilador Sun C ++)

E não se esqueça que, com a eliminação de código morto da DLL, pode ser realizada. Dependendo do idioma, o código da DLL também pode não ser de maneira ideal. As funções virtuais são sempre virtuais porque o compilador não sabe se um cliente está substituindo -o.

Por esses motivos, caso não haja necessidade real de DLLs, basta usar a compilação estática.

Editar (para responder ao comentário, pelo usuário sublinhado)

Aqui está um bom recurso sobre o problema de código independente da posição http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-shared-libraries/

Conforme explicado, o X86 não os tem Afaik para qualquer outra coisa, depois de 15 bits de salto e não por saltos e chamadas incondicionais. É por isso que as funções (de geradores) com mais de 32k sempre foram um problema e precisavam de trampolins incorporados.

Mas no popular sistema operacional x86 como o Linux, você simplesmente não precisa se importar se o arquivo SO/DLL não for gerado com o gcc trocar -fpic (que reforça o uso das tabelas de salto indiretas). Porque se não o fizer, o código é corrigido como um vinculador normal o mudaria. Mas, ao fazer isso, torna o segmento de código não compartilhável e precisaria de um mapeamento completo do código do disco para a memória e tocando tudo antes que ele possa ser usado (esvaziando a maioria dos caches, atingindo os TLBs) etc. Quando isso foi considerado lento ... muito lento.

Então você não teria mais nenhum benefício.

Não me lembro do que o sistema operacional (Solaris ou FreeBSD) me deu problemas com meu sistema de construção do Unix, porque eu simplesmente não estava fazendo isso e me perguntei por que ele caiu até que eu me apliquei -fPIC para gcc.

A ligação dinâmica é a única maneira prática de atender a alguns requisitos de licença, como o LGPL.

Eu concordo com os pontos que o dnmckee menciona, mais:

  • Os aplicativos estaticamente vinculados podem ser mais fáceis de implantar, pois há menos ou nenhuma dependência de arquivo adicional (.dll / .so) que pode causar problemas quando estão ausentes ou instalados no local errado.

Um motivo para fazer uma compilação estaticamente vinculada é verificar se você tem um fechamento completo para o executável, ou seja, que todas as referências de símbolo são resolvidas corretamente.

Como parte de um grande sistema que estava sendo construído e testado usando integração contínua, os testes de regressão noturna foram executados usando uma versão estaticamente vinculada dos executáveis. Ocasionalmente, veríamos que um símbolo não resolveria e o link estático falharia, mesmo que o executável dinamicamente vinculado vinculasse com sucesso.

Isso geralmente estava ocorrendo quando os símbolos que estavam sentados profundamente dentro dos Libs compartilhados tinham um nome incorreto e, portanto, não seriam estaticamente vinculados. O vinculador dinâmico não resolve completamente todos os símbolos, independentemente de usar a avaliação de profundidade primeiro ou de largura, para que você possa terminar com um executável vinculado dinamicamente que não tenha fechamento total.

1/ eu estive em projetos onde a ligação dinâmica vs vinculação estática foi aferido e a diferença não era determinado pequena o suficiente para alternar para dynamic linking (eu não era parte do teste, eu só sei que a conclusão)

2/ vinculação Dinâmica é frequentemente associada com a PIC (Posição Independente de um código, o Código que não precisa ser modificado, dependendo do endereço em que ele é carregado).Dependendo da arquitetura do PIC pode trazer outro abrandamento, mas é necessário, a fim de se beneficiar da partilha de uma biblioteca dinamicamente vinculada entre dois executável (e mesmo processo do executável do mesmo, se o sistema operacional usar a aleatorização da carga de endereço como uma medida de segurança).Eu não tenho certeza de que todos OS permitem separar os dois conceitos, mas Solaris e Linux e ISTR que HP-UX faz tão bem.

3/ eu tenho outros projetos que usado de ligação dinâmicos para fácil "patch" recurso.Mas esse "fácil patch" faz a distribuição de pequena correção um pouco mais fácil e de uma complicada de um controle de versão de pesadelo.Nós, muitas vezes, acabou por ter de empurrar tudo além de ter que controlar problemas no site do cliente, porque a versão errada foi token.

Minha conclusão é que eu tinha usado a vinculação estática isentos:

  • para coisas como plugins que dependem de ligação dinâmica

  • quando a partilha é importante (grandes bibliotecas utilizadas por vários processos ao mesmo tempo, como C/C++ runtime, GUI bibliotecas, ...que muitas vezes são gerenciados de forma independente e para o qual a ABI é estritamente definido)

Se quiser usar o "fácil patch", eu diria que as bibliotecas têm de ser geridos como as grandes bibliotecas acima:eles devem ser quase independente, com um definido ABI que não deve ser alterado por correções.

este Discuta em grande detalhe sobre as bibliotecas compartilhadas no Linux e nas implicações de desempenho.

É muito simples, realmente. Quando você faz uma alteração no seu código -fonte, deseja esperar 10 minutos para que ele construa ou 20 segundos? Vinte segundos é tudo o que posso suportar. Além disso, saio da espada ou começo a pensar em como posso usar compilação e vinculação separados para trazê -la de volta à zona de conforto.

Em sistemas semelhantes ao UNIX, a ligação dinâmica pode dificultar a vida de 'raiz' usar um aplicativo com as bibliotecas compartilhadas instaladas em locais fora do caminho. Isso ocorre porque o ligante dinâmico geralmente não presta atenção ao LD_LIBRARY_PATH ou ao seu equivalente a processos com privilégios de raiz. Às vezes, então, a ligação estática salva o dia.

Como alternativa, o processo de instalação precisa localizar as bibliotecas, mas isso pode dificultar para várias versões do software coexistir na máquina.

A ligação dinâmica requer tempo extra para o sistema operacional encontrar a biblioteca dinâmica e carregá -la. Com a ligação estática, tudo está junto e é uma carga de um tiro na memória.

Veja também Dll Inferno. Este é o cenário em que a DLL que o sistema operacional não é o que acompanha seu aplicativo ou a versão que seu aplicativo espera.

O melhor exemplo para a ligação dinâmica é que a biblioteca depende do hardware usado. Nos tempos antigos, a biblioteca de matemática C era decidida ser dinâmica, para que cada plataforma possa usar todos os recursos do processador para otimizá -la.

Um exemplo ainda melhor pode ser o OpenGL. O OpenGL é uma API que é implementada de maneira diferente pela AMD e NVIDIA. E você não pode usar uma implementação da NVIDIA em um cartão AMD, porque o hardware é diferente. Você não pode vincular o OpenGL estaticamente ao seu programa, por causa disso. A ligação dinâmica é usada aqui para permitir que a API seja otimizada para todas as plataformas.

Outro problema ainda não foi discutido é a correção de bugs na biblioteca.

Com a vinculação estática, você não só tem que reconstruir a biblioteca, mas vai ter que ligar novamente e redestribute o executável.Se a biblioteca for utilizado apenas em um executável, isso não pode ser um problema.Mas o mais executáveis que precisam ser vinculados novamente e redistribuído, maior é a dor.

Com a ligação dinâmica, você acabou de recriar e redistribuir a biblioteca dinâmica e está feito.

A ligação estática fornece apenas um único exe, para fazer uma alteração necessária para recompilar todo o seu programa. Considerando que, na ligação dinâmica, você precisa fazer alterações apenas na DLL e quando você executar seu exe, as alterações serão captadas no tempo de execução. É mais fácil fornecer atualizações e correções de bugs por vinculação dinâmica (por exemplo: Windows).

Existe um vasto e crescente número de sistemas onde um nível extremo de vinculação estática pode ter um enorme impacto positivo sobre as aplicações e o desempenho do sistema.

Refiro-me ao que muitas vezes são chamados de "sistemas embarcados", muitos dos quais estão agora usando cada vez mais sistemas operacionais de propósito geral, e esses sistemas são usados para tudo que se possa imaginar.

Extremamente exemplo comum são dispositivos que utilizam os sistemas GNU/Linux usando Busybox.Eu tenho levado isso ao extremo com NetBSD a construção de um arranque i386 (32-bit) imagem do sistema que inclui um kernel e o seu sistema de ficheiros raiz, este último, que contém uma única estática-ligados (por crunchgen) binário com hard-links para todos os programas que em si contém todos (bem, na última contagem, 274) do padrão completo, programas de sistema (a maioria, exceto o toolchain), e é menos do que 20 megabytes de tamanho (e, provavelmente, corre muito confortavelmente em um sistema com apenas 64 mb de memória (mesmo com o sistema de arquivos raiz descomprimida e completamente na RAM), embora eu tenha sido incapaz de encontrar uma tão pequena para testá-lo em).

Ele foi mencionado em posts anteriores que o tempo de start-up de um estático-vinculado binários é mais rápido (e pode ser um monte mais rápido), mas que é apenas uma parte da imagem, especialmente quando todos do código objecto é ligado no mesmo arquivo, e, ainda mais, especialmente quando o sistema operacional suporta a demanda de paginação de código diretamente do arquivo executável.Neste cenário ideal, o tempo de inicialização de programas literalmente insignificante, já que quase todas as páginas de código já estará na memória e estar em uso pelo shell (e e init quaisquer outros processos em segundo plano que pode ser executado), mesmo se o pedido de programa não tenha sido executado desde a inicialização, pois talvez apenas uma página de memória precisa ser carregado para cumprir os requisitos de tempo de execução do programa.

No entanto, que ainda não é a história toda.Eu normalmente também construir e utilizar o sistema operacional NetBSD instala para o meu pleno desenvolvimento de sistemas estáticos-a vinculação de todos os binários.Mesmo que isso leva a uma quantidade enorme de mais espaço em disco (~6.6 GB total para x86_64 com tudo, incluindo o conjunto de ferramentas e X11 estático-vinculado) (especialmente se se mantém cheia de símbolos de depuração tabelas disponíveis para todos os programas de outro ~2.5 GB), o resultado ainda é mais rápido no geral, e para algumas tarefas, mesmo utiliza menos memória do que um típico ligado dinâmica do sistema que se propõe a compartilhar a biblioteca de páginas de código.O disco é barato (mesmo disco rápido), e a sua memória, frequentemente utilizados em cache de disco, arquivos também é relativamente barato, mas ciclos de CPU realmente não o são, e pagando a ld.so custo inicial para cada processo que se inicia todos o tempo começa vai demorar horas e horas de ciclos de CPU longe de tarefas que exigem a partida de muitos processos, especialmente quando os mesmos programas são usados repetidamente, tais como compiladores em um sistema de desenvolvimento.Estática-vinculado conjunto de ferramentas de programas pode reduzir todo o sistema operativo multi-arquitetura de construir vezes para minha sistemas horas.Eu ainda tenho que construir o conjunto de ferramentas para o meu único crunchgen'ed binário, mas eu suspeito que quando eu faço haverá mais horas de tempo de compilação guardada por causa da vitória para o cache da CPU.

A vinculação estática inclui os arquivos que o programa precisa em um único arquivo executável.

Vinculação dinâmica é o que você poderia considerar que o de costume, ele faz um executável que ainda requer DLLs e como estar no mesmo diretório (ou a Dll pode ser na pasta de sistema).

(DLL = de vínculo dinâmico biblioteca)

Ligado dinamicamente executáveis compilados mais rápido e não são tão pesados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top