Windows ボックスで新しいプロセスを作成すると、Linux よりもコストがかかると聞いたことがあります。これは本当ですか?より高価な技術的な理由を説明し、その理由の背後にある設計上の決定の歴史的な理由を提供できますか?
10 に答える
mweerden: NT は最初からマルチユーザー向けに設計されているため、これは理由にはなりません。ただし、プロセスの作成は、NT では Unix よりも重要な役割を果たしません。Unix とは対照的に、NT ではマルチプロセッシングよりもマルチスレッドが優先されます。
ロブ、COW を使用すると fork が比較的安価であることは事実ですが、実際のところ、fork の後には主に exec が続きます。また、exec はすべてのイメージもロードする必要があります。したがって、フォークのパフォーマンスについて議論することは、真実の一部にすぎません。
プロセス作成の速度について議論するときは、NT と Windows/Win32 を区別することをお勧めします。NT (つまり、カーネル自体) に関する限り、プロセスの作成 (NtCreateProcess) とスレッドの作成 (NtCreateThread) が平均的な Unix のように大幅に遅いとは思いません。もう少し進んでいる可能性がありますが、パフォーマンスの違いの主な理由はわかりません。
ただし、Win32 を見ると、プロセスの作成にかなりのオーバーヘッドが追加されていることがわかります。1 つには、LPC を含むプロセスの作成について CSRSS に通知する必要があります。少なくとも kernel32 を追加でロードする必要があり、プロセスが本格的な Win32 プロセスであると見なされる前に、多数の追加のブックキーピング作業項目を実行する必要があります。また、マニフェストの解析、イメージに互換性シムが必要かどうかのチェック、ソフトウェア制限ポリシーが適用されるかどうかのチェック、やだやだによって課せられるすべての追加オーバーヘッドを忘れないでください。
とはいえ、プロセス、VA スペース、および初期スレッドの未加工の作成に加えて、実行する必要があるすべての小さなことの合計で、全体的な速度低下が見られます。しかし、最初に述べたように、マルチタスクよりもマルチスレッドが好まれるため、この追加費用によって深刻な影響を受ける唯一のソフトウェアは、不十分に移植された Unix ソフトウェアです。この状況は、Chrome や IE8 などのソフトウェアが突然マルチプロセッシングの利点を再発見し、頻繁にプロセスを起動および破棄し始めると変わりますが...
Unix には、現在のプロセスを 2 つに「分割」する「fork」システム コールがあり、最初のプロセスと同一の 2 番目のプロセスを提供します (fork 呼び出しからの戻りをモジュロ)。新しいプロセスのアドレス空間はすでに稼働しているため、これは Windows で「CreateProcess」を呼び出して exe イメージや関連する dll などをロードするよりも安価です。
フォークの場合、OS は、両方の新しいプロセスに関連付けられたメモリ ページに「コピー オン ライト」セマンティクスを使用して、それぞれが後で変更するページの独自のコピーを確実に取得できるようにします。
JP の発言に加えて、ほとんどのオーバーヘッドはプロセスの Win32 スタートアップに属しています。
Windows NT カーネルは実際に COW フォークをサポートしています。SFU (Microsoft の Windows 用 UNIX 環境) はそれらを使用します。ただし、Win32 は fork をサポートしていません。SFU プロセスは Win32 プロセスではありません。SFU は Win32 と直交しています。どちらも同じカーネル上に構築された環境サブシステムです。
へのアウトプロセス LPC 呼び出しに加えて、CSRSS
XP 以降では、アプリケーション互換性データベースでプログラムを検索するために、アプリケーション互換性エンジンへのアウトプロセス呼び出しがあります。この手順により、Microsoftがパフォーマンス上の理由からWS2003 で互換性エンジンを無効にするグループ ポリシー オプションを提供するのに十分なオーバーヘッドが発生します。
Win32 ランタイム ライブラリ (kernel32.dll など) も、UNIX、SFU、またはネイティブ プロセスには適用されない多くのレジストリの読み取りと起動時の初期化を行います。
ネイティブ プロセス (環境サブシステムなし) は、作成が非常に高速です。SFU は Win32 よりもプロセスの作成が少ないため、プロセスの作成も高速です。
2019 年の更新: LXSS を追加: Linux 用 Windows サブシステム
Windows 10 の SFU を置き換えるのは、LXSS 環境サブシステムです。これは 100% カーネル モードであり、Win32 が引き続き使用する IPC は必要ありません。これらのプロセスの syscall は lxss.sys/lxcore.sys に直接送信されるため、 fork() またはその他のプロセス作成呼び出しは、作成者の合計 1 つのシステム コールしかかかりません。[インスタンスと呼ばれるデータ領域] は、すべての LX プロセス、スレッド、および実行時の状態を追跡します。
LXSS プロセスは、Win32 プロセスではなく、ネイティブ プロセスに基づいています。互換性エンジンなどの Win32 固有のものはすべて、まったく関与していません。
Rob Walker の回答に加えて: 最近では、Native POSIX Thread Library のようなものがあります - 必要に応じて。しかし、長い間、UNIX の世界で作業を「委譲」する唯一の方法は fork() を使用することでした (そして、多くの状況で今でも好まれています)。たとえば、ある種のソケットサーバー
socket_accept() フォーク() もし(子供) ハンドルリクエスト() そうしないと goOnBeingParent()したがって、フォークの実装は高速である必要があり、多くの最適化が時間をかけて実装されてきました。Microsoft は、新しいプロセスを作成してプロセス間通信を使用する代わりに、CreateThread またはファイバーさえも承認しました。CreateProcess を fork と比較するのは「公平」ではないと思います。それらは交換可能ではないからです。fork/exec を CreateProcess と比較する方がおそらく適切です。
この問題の鍵は、両方のシステムの歴史的な使用法にあると思います。Windows (およびそれ以前の DOS) は、もともとパーソナルコンピュータ用のシングル ユーザー システムでした。そのため、これらのシステムは通常、常に多くのプロセスを作成する必要はありません。(非常に) 簡単に言えば、プロセスは、この 1 人の孤独なユーザーが要求した場合にのみ作成されます (そして、私たち人間は比較的速く動作しません)。
Unix ベースのシステムは、もともとマルチユーザー システムおよびサーバーでした。特に後者の場合、特定のジョブを処理するためにプロセスを分割するプロセス (メールや http デーモンなど) を持つことは珍しくありません (たとえば、1 つの着信接続を処理します)。これを行う際の重要な要素は、安価な方法 (Rob Walker ( 47865fork
)が述べたように、最初は新しく作成されたプロセスに同じメモリを使用する) です。これは、新しいプロセスが必要なすべての情報をすぐに取得できるため、非常に便利です。
少なくとも歴史的には、Unix ベースのシステムでプロセスを高速に作成する必要性が、Windows システムよりもはるかに高いことは明らかです。Unix ベースのシステムは依然として非常にプロセス指向であるのに対し、Windows はその歴史から、おそらくよりスレッド指向であったため、これは依然として当てはまると思います (スレッドは応答性の高いアプリケーションを作成するのに役立ちます)。
免責事項: 私は決してこの問題の専門家ではないので、間違っていたらご容赦ください。
簡単な答えは「ソフトウェアレイヤーとコンポーネント」です。
Windows SWアーキテクチャには、Unixには存在しないか、Unixのカーネル内で簡略化および処理される、いくつかの追加のレイヤーとコンポーネントがあります。
Unixでは、forkとexecはカーネルへの直接呼び出しです。
Windowsでは、カーネルAPIは直接使用されず、その上にwin32とその他の特定のコンポーネントがあるため、プロセスの作成は追加のレイヤーを経由してから、新しいプロセスを起動するか、それらのレイヤーとコンポーネントに接続する必要があります。
かなり長い間、研究者や企業は、通常はMachカーネルに基づいて、漠然と同様の方法でUnixを分割しようと試みてきました。よく知られている例はOSXです。しかし、彼らが試みるたびに、それは非常に遅くなり、永久にまたは本番出荷のために、少なくとも部分的にカーネルにピースをマージして戻すことになります。
ええと、多くの「この方法の方が良い」という種類の正当化が行われているようです。
「Showstopper」を読むことで人々は恩恵を受けることができると思います。WindowsNTの開発に関する本。
Windows NTの1つのプロセスでサービスがDLLとして実行される理由は、個別のプロセスとしては遅すぎるためです。
降りて汚い場合は、ライブラリの読み込み戦略が問題であることがわかります。
Unices(一般)では、共有ライブラリ(DLL)コードセグメントが実際に共有されます。
Windows NTは、プロセスごとにDLLのコピーをロードします。これは、ロード後にライブラリコードセグメント(および実行可能コードセグメント)を操作するためです。(データがどこにあるかを教えてくれますか?)
これにより、ライブラリ内のコードセグメントが再利用できなくなります。
したがって、NTプロセスの作成は実際にはかなり高価です。また、欠点として、DLLのメモリへの節約はそれほど多くありませんが、アプリ間の依存関係の問題が発生する可能性があります。
時々、エンジニアリングに戻って、「これを本当にひどく設計するつもりだったとしたら、どのように見えるでしょうか?」と言うのはお金がかかることがあります。
私はかつて非常に気まぐれな組み込みシステムで作業しましたが、ある日それを見て、マイクロ波空洞に電子機器を備えた空洞マグネトロンであることに気づきました。その後、私たちはそれをはるかに安定させました(そして電子レンジのようではありません)。
また、Windows のセキュリティ モデルは UNIX ベースの OS よりもはるかに複雑であり、プロセスの作成中に多くのオーバーヘッドが追加されることにも注意してください。Windows でマルチプロセッシングよりもマルチスレッドが好まれるもう 1 つの理由。
それに加えて、Win マシンでは、CreateProcess 中にウイルス対策ソフトウェアが起動する可能性が最も高いという事実があります。通常、これが最大の速度低下です。