Unixシリーズシステムが新しい関数を呼び出すとき、なぜ新しいプロセスを実行するのですか?

Unixシリーズシステムが新しい関数を呼び出すとき、なぜ新しいプロセスを実行するのですか?

Unixシリーズシステムが動的ライブラリの代わりに関数を呼び出すとき、なぜ新しいプロセスを実行するのですか?新しいプロセスを作成することは、動的ライブラリを呼び出すよりもパフォーマンスの面で高価です。

ベストアンサー1

Unixシリーズシステムは、「新しいプロセスを実行して関数を呼び出す」ことはありません。彼らは(現在)比較的近代的なほとんどすべてのオペレーティングシステムと同様に、共有ライブラリを持っています。

一方、シェルは特定のタスクを実行するために別のプロセスを実行します。しかし、すべてではありません。これには、シェルから直接(または共有ライブラリを介して)最も一般的で単純な操作を実装する組み込み関数があります(echoたとえば、多くのシェルで組み込み関数として実装されています)。
(しかし、Windowscmdシェルはこの点でUnixシェルと変わりません。)

プロセスを作成することは確かに、最新のUnixファミリーシステムでプロセス内の関数呼び出しを実行するよりもコストがかかりますが、それほど大きなコストではありません。カーネルは、次の技術を使用して高速フォークに最適化されています。書き込み中のコピープロセスの「複製」を高速化し、動的ライブラリのテキスト(コード)ページを共有するためのアドレス空間管理に使用されます。

シェルスクリプトから呼び出すことができるコンピュータ上のすべての実行可能ファイルが共有ライブラリとして実装されている場合:

  • シェルを起動するには、次のものが必要です。たくさんこれらすべてを事前ロードするのに必要な時間(およびメモリ)(キャッシュを使用しても動的リンカには実行する重要な作業があり、ライブラリにはテキスト部分だけでなくデータ部分もあります。数千ではなく数百に相当します。ライブラリはここ)
  • 要求に応じて必要なすべてのライブラリをロードする必要があります。プロセスを開始するよりも少し速いかもしれませんが、ここでの利点は非常に弱いです。そして、共有ライブラリのデータ部分は管理するのが非常に困難になります(シェルのグローバル状態は、アドレス空間にロードされている無関係なコードとデータの状態によって異なります)。

したがって、一般的な使用ではおそらく多くの利点が得られず、安定性/複雑さがより重要になります。

別の点は、別々のプロセスモデルが各タスクを非常に効果的に分離することです(仮想メモリの管理と保護の前提)。 「すべてがライブラリです」モデルでは、ユーティリティライブラリのバグがシェル全体を汚染(つまり破損)する可能性があります。一部のランダムユーティリティのバグにより、シェルプロセスが完全に中断される可能性があります。
これは、シェルが実行するプログラムでそのようなエラーを回避できるマルチプロセスモデルの場合には該当しません。

もう一つ:低い結合度。/usr/bin今、ディレクトリの内容を見ると次のようになります。

  • ELF 64ビット実行可能ファイル、
  • ELF 32ビット実行可能ファイル、
  • パールスクリプト、
  • シェルスクリプト(一部はJavaプログラムを実行します)、
  • ルビースクリプトと
  • Pythonスクリプト

...おそらく私は最もクールなシステムを持っていません。同じプロセスで最初の2つのタイプを混在させることはできません。他の人のために通訳を置くことはまったく実用的ではありません。
「ネイティブバイナリ」ファイル形式のみを見る場合でも、「ユーティリティ」間のインタフェースは単純なストリームと終了コードなので、作業がより簡単になります。
ユーティリティの唯一の要件は、オペレーティングシステムのABIおよびシステムコールを実装することです。異なるユーティリティ間には依存関係がありません。 In-Processインターフェイスの場合、「すべてはこれらのフラグ/設定を使用してコンパイラYのバージョンXにコンパイルする必要があります」などの規定を課さない限り、これは非常に困難または不可能です。

プロセス内の呼び出しがパフォーマンスに大きな影響を与えるいくつかのタスクがあり、これらのタスクはシェルから組み込みとしてすでに実行されることがよくあります。残りのケースでは、別々のプロセスモデルが非常にうまく機能し、柔軟性が高い利点です。

おすすめ記事