458

特定の状況で動的リンクよりも静的リンクを選択したり、その逆を選択したりする魅力的なパフォーマンス上の理由はありますか? 私は次のことを聞いたり読んだりしましたが、その真実性を保証するのに十分な知識がありません.

1) 静的リンクと動的リンクの間の実行時パフォーマンスの違いは、通常は無視できます。

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

4

16 に答える 16

393
  • 動的リンクにより、総リソース消費量を削減できます(複数のプロセスが同じライブラリを共有している場合 (もちろん、「同じ」バージョンを含む))。これが、ほとんどの環境でその存在を推進する理由であると私は信じています。ここでの「リソース」には、ディスク容量、RAM、およびキャッシュ容量が含まれます。もちろん、動的リンカーの柔軟性が不十分な場合、DLL 地獄のリスクがあります。
  • ダイナミックリンクとは、バグ修正やライブラリのアップグレードが伝播され、何も出荷する必要なく製品が改善されることを意味します。
  • プラグインは常に動的リンクを呼び出します。
  • 静的リンクとは、コードが非常に限られた環境(起動プロセスの初期、またはレスキュー モード) で実行されることを知ることができることを意味します。
  • 静的リンクを使用すると、さまざまなユーザー環境にバイナリを簡単に配布できます (より大きく、より多くのリソースを必要とするプログラムを送信するという犠牲を払って)。
  • 静的リンクを使用すると、起動時間がわずかに短縮される可能性がありますが、これは、プログラムのサイズと複雑さ、およびOS の読み込み戦略の詳細にある程度依存します。

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


パフォーマンスと効率の問題に対処するには:依存します

古典的に、動的ライブラリはある種の接着層を必要とします。これは、多くの場合、二重ディスパッチまたは関数のアドレス指定における間接的な余分な層を意味し、少し速度が低下する可能性があります (ただし、関数呼び出し時間は実際には実行時間の大部分を占めていますか???)。

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

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

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

パフォーマンスに関する質問に答えるには、常にテストを行う必要があります (また、可能な限り展開環境に近いテスト環境を使用します)。

于 2010-01-03T00:10:20.240 に答える
74

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 ビットのジャンプ範囲以外には AFAIK がなく、無条件のジャンプや呼び出しには対応していません。そのため、32K を超える関数 (ジェネレーターからの) は常に問題であり、埋め込みトランポリンが必要でした。

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

したがって、あなたにはもう何のメリットもありません。

-fPICどの OS (Solaris または FreeBSD) で Unix ビルド システムに問題が発生したか覚えていませんgcc

于 2010-01-03T00:19:39.247 に答える
72

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

于 2010-01-03T05:01:09.637 に答える
47

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

  • 静的にリンクされたアプリケーションは、追加のファイルの依存関係 (.dll / .so) が不足しているか、間違った場所にインストールされている場合に問題を引き起こす可能性があるため、展開が容易になる場合があります。
于 2010-01-03T00:16:24.833 に答える
35

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

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

これは通常、共有ライブラリ内に深く根ざしているシンボルの名前が間違っていて、静的にリンクされない場合に発生していました。動的リンカーは、深さ優先評価または幅優先評価の使用に関係なく、すべてのシンボルを完全に解決するわけではないため、完全なクロージャーを持たない動的にリンクされた実行可能ファイルを完成させることができます。

于 2010-01-03T00:39:37.370 に答える
21

1/ 私は、動的リンクと静的リンクがベンチマークされ、その差が動的リンクに切り替えるのに十分なほど小さいと判断されなかったプロジェクトに参加してきました (私はテストに参加していませんでした。結論を知っているだけです)。

2/ 動的リンクは、多くの場合、PIC (位置独立コード、ロードされるアドレスに応じて変更する必要のないコード) に関連付けられています。アーキテクチャによっては、PIC は別の速度低下をもたらす可能性がありますが、動的にリンクされたライブラリを 2 つの実行可能ファイル (および OS がセキュリティ対策としてロード アドレスのランダム化を使用している場合は同じ実行可能ファイルの 2 つのプロセス) 間で共有する利点を得るために必要です。すべての OS で 2 つの概念を分離できるかどうかはわかりませんが、Solaris と Linux では分離でき、HP-UX では ISTR も分離できます。

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

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

  • 動的リンクに依存するプラグインなどの場合

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

「簡単なパッチ」を使用したい場合は、ライブラリを上記の大きなライブラリのように管理する必要があると主張します。修正によって変更されてはならない定義済みの ABI とほぼ独立している必要があります。

于 2010-01-03T10:03:18.500 に答える
11

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

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

于 2015-02-12T01:52:32.717 に答える
11

とてもシンプルです。ソース コードに変更を加えた場合、ビルドが完了するまで 10 分待ちますか、それとも 20 秒待ちますか? 私が我慢できるのは20秒だけです。それを超えて、私は剣を抜くか、別のコンパイルとリンクを使用してそれを快適ゾーンに戻す方法を考え始めます.

于 2010-01-03T00:42:09.140 に答える
10

Unix ライクなシステムでは、動的リンクにより、'root' が人里離れた場所にインストールされた共有ライブラリを使用してアプリケーションを使用することが難しくなる可能性があります。これは、通常、動的リンカーが LD_LIBRARY_PATH または root 権限を持つプロセスの同等のパスに注意を払わないためです。場合によっては、静的リンクで問題が解決することがあります。

別の方法として、インストール プロセスでライブラリを見つける必要がありますが、その場合、ソフトウェアの複数のバージョンがマシン上で共存することが難しくなる可能性があります。

于 2010-01-04T19:15:05.790 に答える
9

ダイナミック リンクでは、OS がダイナミック ライブラリを見つけてロードするために余分な時間が必要です。静的リンクを使用すると、すべてがまとめられ、メモリへのワンショット ロードになります。

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

于 2010-01-03T00:40:53.250 に答える
7

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

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

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

于 2010-01-03T08:31:46.533 に答える
3

静的リンクでは、プログラム全体を再コンパイルする必要がある変更を行うために、1 つの exe しか提供されません。動的リンクでは、dll のみを変更する必要があり、exe を実行すると、実行時に変更が取得されます。動的リンク (例: Windows) による更新とバグ修正の提供は簡単です。

于 2016-10-11T01:35:30.990 に答える
3

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

私はしばしば「組み込みシステム」と呼ばれるものに言及します。その多くは現在、ますます汎用のオペレーティング システムを使用しており、これらのシステムは想像できるすべてのものに使用されています。

非常に一般的な例は、Busyboxを使用する GNU/Linux システムを使用するデバイスです。私は、カーネルとそのルートファイルシステムの両方を含む起動可能な i386 (32 ビット) システムイメージを構築することで、 NetBSDcrunchgenでこれを極限まで進めました。標準のフル機能システム プログラム (ほとんどはツールチェーンを除く) のすべて(最終的には 274 個) を含むすべてのプログラムで、サイズは 20 メガバイト未満です (そして、わずか 64 MB のシステムでおそらく非常に快適に実行されます)。(ルート ファイルシステムが圧縮されておらず、完全に RAM に格納されている場合でも)、テストするのに非常に小さいものを見つけることができませんでした)。

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

しかし、それだけではありません。また、通常、すべてのバイナリを静的リンクすることにより、完全な開発システム用の NetBSD オペレーティング システムのインストールをビルドして使用します。これには非常に多くのディスク容量が必要ですが (ツールチェーンと X11 静的リンクを含むすべてのものを含む x86_64 の合計で最大 6.6 GB) (特に、すべてのプログラムで完全なデバッグ シンボル テーブルを使用できるようにしておくと、別の最大 2.5 GB になります)、それでも結果は変わりません。全体的に高速に実行され、一部のタスクでは、ライブラリ コード ページを共有することを目的とした典型的なダイナミック リンク システムよりも少ないメモリしか使用しません。ld.soディスクは安価で (高速ディスクでも)、頻繁に使用されるディスク ファイルをキャッシュするためのメモリも比較的安価ですが、CPU サイクルは実際にはそうではありません特に開発システムのコンパイラーなど、同じプログラムが何度も何度も使用される場合は、多くのプロセスを開始する必要があるタスクから何時間も CPU サイクルが離れます。静的にリンクされたツールチェーン プログラムは、システム全体の OS マルチアーキテクチャ ビルド時間を数時間短縮できます。ツールチェーンをシングルcrunchgen'ed バイナリにビルドする必要はまだありませんが、そうすると、CPU キャッシュが有利になるため、ビルド時間がさらに短縮されるのではないかと思います。

于 2017-07-28T22:19:30.220 に答える