web-dev-qa-db-ja.com

静的リンクと動的リンク

特定の状況において、動的リンクよりも静的リンクを選択する、またはその逆を選択する必要があるパフォーマンス上の理由はありますか?私は以下のことを聞いたり読んだりしましたが、その正当性を保証するためにこの問題について十分に知りません。

1)静的リンクと動的リンクの実行時パフォーマンスの違いは、通常ごくわずかです。

2)(1)は、プロファイルデータを使用してプログラムのホットパスを最適化するプロファイリングコンパイラを使用する場合は当てはまりません。静的リンクを使用すると、コンパイラはコードとライブラリコードの両方を最適化できるからです。動的リンクを使用すると、コードだけを最適化できます。ほとんどの時間がライブラリコードの実行に費やされている場合、これは大きな違いを生む可能性があります。それ以外の場合は、(1)が適用されます。

372
Eloff
  • 動的リンクにより、総リソース消費を削減できます(複数のプロセス共有の場合同じライブラリ(もちろん「同じ」のバージョンを含む)。これは、ほとんどの環境でその存在を促進する議論だと思います。ここで、「リソース」には、ディスク容量、RAM、およびキャッシュ容量が含まれます。もちろん、動的リンカーの柔軟性が不十分な場合、 DLL hell のリスクがあります。
  • ダイナミックリンクは、バグ修正とライブラリのアップグレード伝播を意味します何も出荷する必要のないあなたの製品。
  • プラグインは常にdynamicリンクを呼び出します。
  • 静的リンクは、コードが非常に制限された環境で実行されることを知ることができることを意味します(初期のブートプロセス、またはレスキューモード)。
  • 静的リンクにより、バイナリをさまざまなユーザー環境への配布が容易になりますより大きく、より多くのリソースを必要とするプログラムを送信するコスト。
  • 静的リンクにより、わずかにより高速な起動時間が可能になりますが、これは一部に依存しますプログラムのサイズと複雑さの両方の程度およびOSのロード戦略の詳細。

コメントやその他の回答に非常に関連性の高い提案を含めるように編集します。これを破る方法は、実行する環境に大きく依存します。最小限の組み込みシステムでは、動的リンクをサポートするのに十分なリソースがない場合があります。わずかに大きい小さなシステムは、動的リンクのメモリを十分に小さくして、動的リンクによるRAMの節約を非常に魅力的なものにするため、動的リンクをサポートできます。本格的な消費者向けPCには、Markが指摘しているように、膨大なリソースがあります。おそらく、この問題についての利便性の問題を考えさせることができます。


パフォーマンスと効率の問題に対処するには:it depend

古典的に、動的ライブラリには、多くの場合、関数のアドレス指定で二重ディスパッチまたは間接的な余分な層を意味する何らかの種類の接着層が必要であり、少し速度がかかります(ただし、関数呼び出し時間は実際には実行時間の大部分ですか?)。

ただし、すべてが同じライブラリを頻繁に呼び出す複数のプロセスを実行している場合、静的リンクの使用と比較して動的リンクを使用すると、キャッシュラインを節約できます(したがって、実行パフォーマンスが向上します)。 (最新のOSが、静的にリンクされたバイナリ内の同一のセグメントに気付くほど賢くない場合を除き、難しいようです。

別の問題:読み込み時間。ある時点でロードコストを支払います。この費用を支払う時期は、OSの動作方法と使用するリンクによって異なります。たぶん、あなたはあなたがそれを必要とすることがわかるまで、それを支払うことを延期したいかもしれません。

Static-vs-dynamicリンクは伝統的にではなく最適化の問題であることに注意してください。両方ともオブジェクトファイルまで個別のコンパイルを伴うからです。ただし、これは必須ではありません。コンパイラは原則として、最初にダイジェストASTフォームに「静的ライブラリ」を「コンパイル」し、メインコード用に生成されたASTにそれらのASTを追加して「リンク」できます、したがってグローバルな最適化を強化します。私が使用しているシステムはどれもこれを行っていないので、どのように機能するかについてコメントすることはできません。

パフォーマンスの質問に答える方法は、テストによるalwaysです(可能な限りデプロイメント環境に近いテスト環境を使用します)。

330
dmckee

動的リンクは、 LGPL などのライセンス要件を満たすための唯一の実用的な方法です。

64
Mark Ransom

1)はDLL関数の呼び出しが常に追加の間接ジャンプを使用しているという事実に基づいています。今日、これは通常ごくわずかです。 DLLの中では、i386 CPUには、位置に依存しないコードを生成できないため、いくつかのオーバーヘッドがあります。 AMD64では、ジャンプはプログラムカウンタと相対的な場合があるため、これは大きな改善です。

2)これは正しいです。プロファイリングによって導かれる最適化を使用すると、通常10から15パーセントのパフォーマンスを達成できます。 CPU速度が限界に達したので、やる価値があるかもしれません。

(3)リンカは、キャッシュレベルの高いミスを最小限に抑えるために、キャッシュをより効率的にグループ化するように関数を配置することができます。また、アプリケーションの起動時間に特に影響を与える可能性があります(Sun C++コンパイラで見た結果に基づく)。

また、DLLを使用すると、デッドコードの削除を実行できないことを忘れないでください。言語によっては、DLLコードも最適ではない可能性があります。コンパイラはクライアントが上書きしているかどうかわからないため、仮想関数は常に仮想です。

これらの理由から、DLLを実際に必要としない場合は、静的コンパイルを使用してください。

EDIT(コメントに答えるために、ユーザーの下線で)

これは位置に依存しないコードの問題についての良いリソースです http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

説明したように、x86は15ビットのジャンプ範囲以外にはそれを知らず、無条件のジャンプや呼び出しにはそれを知らない。 32Kを超える関数(ジェネレータからの)が常に問題になり、組み込みトランポリンを必要としていた理由はそれだけです。

しかし、Linuxのような一般的なx86 OSでは、SO/DLLファイルがgccスイッチ-fpic(間接ジャンプテーブルの使用を強制する)で生成されていなくても構いません。そうでなければ、通常のリンカが再配置するようにコードが修正されるだけです。しかしこれをしている間はコードセグメントを共有不可能にし、それを使用する前にディスクからメモリへのコードのフルマッピングとそれに触れる必要があるでしょう(ほとんどのキャッシュを空にする、TLBを押す)など。これが遅いと考えられていたとき...遅すぎる。

だからあなたはもう何の利益もないでしょう。

私は私のUnixビルドシステムで私がどんなOS(SolarisまたはFreeBSD)を使って問題を起こしたのかを思い出しません。なぜなら私は-fPICgccに適用するまでクラッシュしたのか疑問に思いました。

64
Lothar

私はdnmckeeが言及している点に同意します、さらに:

  • 静的にリンクされたアプリケーションは、見つからない場合や間違った場所にインストールされた場合に問題を引き起こす可能性のある追加のファイル依存関係(.dll/.so)が少ないかまったくないため、展開が容易になる可能性があります。
42
stakx

静的にリンクされたビルドをする1つの理由は、あなたが実行ファイルを完全に閉じていること、すなわちすべてのシンボル参照が正しく解決されていることを確かめることです。

継続的インテグレーションを使用して構築およびテストされていた大規模システムの一部として、夜間回帰テストは静的にリンクされたバージョンの実行可能ファイルを使用して実行されました。場合によっては、動的にリンクされた実行可能ファイルが正常にリンクされても、シンボルが解決されず静的リンクが失敗することがあります。

これは通常、共有ライブラリ内の奥深くにあるシンボルのスペルミスがあるために静的にリンクされない場合に発生していました。動的リンカーは、深さ優先または幅優先評価を使用しているかどうかにかかわらず、すべてのシンボルを完全に解決するわけではないので、完全クロージャを持たない動的にリンクされた実行可能ファイルで終わることができます。

32
Rob Wells

1 /ダイナミックリンクとスタティックリンクのベンチマークテストが行​​われていて、その違いがダイナミックリンクに切り替えるほど小さいとは判断されていません(テストの一部ではなかったので、結論を知っているだけです)

2 /動的リンクはしばしばPIC(Position Independent Code、ロードされたアドレスに応じて修正する必要のないコード)に関連付けられています。アーキテクチャによっては、PICはもう少し遅くなるかもしれませんが、動的にリンクされたライブラリを2つの実行可能ファイル間で共有するというメリットがあります。すべてのOSがこの2つの概念を区別できるかどうかはわかりませんが、SolarisとLinux、およびHP-UXのISTRもそうです。

3 /私は "簡単なパッチ"機能のために動的リンクを使った他のプロジェクトに取り組んでいます。しかし、この「簡単なパッチ」は小さな修正の配布をもう少し簡単にし、複雑なものをバージョン管理の悪夢にします。間違ったバージョンはトークンだったので、私たちはよくすべてをプッシュしなければならず、カスタマーサイトで問題を追跡しなければならなかったことがよくありました。

私の結論は、静的リンクを使用したのは例外です。

  • 動的リンクに依存するプラグインのようなもの用

  • 共有が重要な場合(C/C++ランタイム、GUIライブラリなど、同時に複数のプロセスで使用される大きなライブラリ... ...これらは独立して管理され、ABIは厳密に定義されていることが多い)

"easy patch"を使いたいのなら、ライブラリは上記の大きなライブラリのように管理されなければならないと主張するでしょう。

21
AProgrammer

この では、Linux上の共有ライブラリとパフォーマンスへの影響について詳しく説明します。

20
nos

本当に簡単です。あなたがあなたのソースコードを変更するとき、あなたはそれが構築されるのを10分待ちますか、それとも20秒ですか? 20秒で我慢できます。それを超えて、私は剣から抜け出すか、または私がどのように私がそれを快適ゾーンに戻すために別々の編集とリンクを使うことができるかについて考え始めます。

11
Hans Passant

Unixライクなシステムでは、動的リンクは 'root'が邪魔にならない場所にインストールされた共有ライブラリを持つアプリケーションを使うのを困難にします。これは、動的リンカは一般に、ルート権限を持つプロセスに対してLD_LIBRARY_PATHまたはそれに相当するものに注意を払わないためです。時々、それで、静的なリンクは日を節約します。

あるいは、インストールプロセスでライブラリを検索する必要がありますが、その場合、複数のバージョンのソフトウェアをマシンに共存させることが難しくなります。

10

動的リンクは、OSが動的ライブラリを見つけてロードするのに余分な時間が必要です。静的リンクでは、すべてが一緒になっており、メモリへのワンショットロードです。

また、 DLL Hell も参照してください。これは、OSがロードするDLLが、アプリケーションに付属しているもの、またはアプリケーションが想定しているバージョンではないシナリオです。

7
Thomas Matthews

動的リンクの最良の例は、ライブラリが使用されているハードウェアに依存している場合です。昔はC数学ライブラリは動的であると決定されました、それで各プラットフォームはそれを最適化するためにすべてのプロセッサ能力を使うことができます。

さらに良い例はOpenGLかもしれません。 OpenGlはAMDとNVidiaによって異なる方法で実装されているAPIです。ハードウェアが異なるため、AMDカードでNVidiaの実装を使用することはできません。そのため、OpenGLをあなたのプログラムに静的にリンクすることはできません。ここでは動的リンクを使用して、すべてのプラットフォーム用にAPIを最適化します。

7
Arne

まだ議論されていないもう一つの問題は、ライブラリのバグを修正することです。

静的リンクでは、ライブラリを再構築するだけでなく、実行可能ファイルを再リンクして再配布する必要があります。ライブラリが1つの実行可能ファイルで使用されているだけであれば、これは問題にならない可能性があります。しかし、再リンクして再配布する必要がある実行可能ファイルが多いほど、痛みが大きくなります。

動的リンクでは、動的ライブラリを再構築して再配布するだけで完了です。

5

静的リンクでは、プログラム全体を再コンパイルするために必要な変更を加えるために、単一のexeのみが与えられます。動的リンクでは、dllとexeファイルを実行するときにのみ変更を加える必要がありますが、変更は実行時に反映されます。動的リンクによる更新とバグ修正を提供する方が簡単です(例:windows)。

3

極端なレベルの静的リンクがアプリケーションやシステムパフォーマンスに多大なプラスの影響を与える可能性がある、膨大で増え続けるシステムがあります。

私はよく「組み込みシステム」と呼ばれるものを参照しますが、その多くは現在汎用オペレーティングシステムを使用するようになっており、これらのシステムは考えられるすべてのものに使用されています。

非常に一般的な例は、 Busybox を使用してGNU/Linuxシステムを使用しているデバイスです。カーネルとそのルートファイルシステムの両方を含むブート可能なi386(32ビット)システムイメージを構築することによって、 NetBSD でこれを極端にしました。後者は、それ自体が標準フル機能のallを含む(---)最後のカウント274までのハードリンクを持つ(crunchgenによる)単一の静的リンクバイナリを含みます。システムプログラム(ほとんどの場合はツールチェーンを除く)で、サイズは20メガバイト未満です(おそらく64MBのメモリしかないシステムでは(ルートを含めても)非常に快適に動作します。私はそれをテストするためにそれほど小さいものを見つけることができませんでしたが。

静的リンクバイナリの起動時間は速い(そしてlot速い)ことが以前の記事で述べられていましたが、それはほんの一部です特に、すべてのオブジェクトコードが同じファイルにリンクされている場合、およびオペレーティングシステムが実行可能ファイルから直接コードのデマンドページングをサポートしている場合はなおさらです。この理想的なシナリオでは、プログラムの起動時間はliterallyと無視できます。コードのほとんどすべてのページがすでにメモリ内にあり、シェル(およびその他のinit)によって使用されているからです。要求されたプログラムが起動後に実行されたことがない場合でも、プログラムの実行時の要件を満たすために1ページのメモリしかロードされないため、実行中のバックグラウンドプロセス).

しかし、それだけではありません。私は通常、すべてのバイナリを静的にリンクすることによって、私の完全な開発システム用のNetBSDオペレーティングシステムのインストールを構築して使用します。これは莫大な量のディスクスペース(ツールチェーンとX11静的リンクを含むすべてを含むx86_64で合計約6.6GB)を消費しますが(特にすべてのプログラムで利用可能なフルデバッグシンボルテーブルをさらに〜2.5GB)ライブラリコードページを共有することを目的としている一般的なダイナミックリンクシステムよりも、全体的に高速で実行されます。ディスクは安価で(高速ディスクでも)、頻繁に使用されるディスクファイルをキャッシュするためのメモリも比較的安価ですが、CPUサイクルは実際にはそうではなく、開始するすべてのプロセスにld.so起動コストを払いますevery特に開発システム上のコンパイラのように同じプログラムが何度も繰り返し使用される場合、多くのプロセスを開始する必要があるタスクから、開始するまでに何時間ものCPUサイクルがかかります。静的にリンクされたツールチェーンプログラムは、hoursによって私のシステムのOS全体のマルチアーキテクチャ構築時間を短縮することができます。ツールチェーンを自分のcrunchgen 'にバイナリ化したバイナリにまだビルドしていませんが、それを実行すると、CPUキャッシュに勝ったためにさらに多くの時間が節約されると思われます。

2
Greg A. Woods

静的リンクは、プログラムが単一の実行可能ファイルに必要とするファイルを含みます。

動的リンクは、あなたがいつも考えていることです、それはまだ同じディレクトリにあるようにDLLを必要とする実行可能ファイルを作ります(またはDLLはシステムフォルダにあるかもしれません)。

(DLL =ダイナミックリンクライブラリ)

動的にリンクされた実行可能ファイルはより速くコンパイルされ、リソースを多く消費しません。

1
Nykal