Windows 秘話既知の DLL のバランスを取る

Raymond Chen

"既知の DLL" と非公式に呼ばれる Windows の機能は、カーネルのモジュール ローダーが特別に処理する DLL (ダイナミック リンク ライブラリ) のリストのことです。ローダーがプログラムを読み込むときに既知の DLL に動的にリンクされていることがわかると、即座にその既知のコピーを使用し、モジュールの読み込み時に通常行う検索アルゴリズムを無視します。確かにかなり不十分ではありますが、これをセキュリティ機能と考える人もいます。しかし、実際には、この機能の目的はセキュリティではありません。既知の DLL は本来はパフォーマンスに関する機能でした。

既知の DLL 機能のしくみは長い時間をかけて変化してきました。あるバージョンの Windows® では、カーネルが既知の DLL のリストを出発点として使用し、既知の DLL からリンクされるすべての DLL を調べ、さらにそれらの DLL からリンクされる DLL を次々に調べていきます。このプロセスでは、すべての依存関係の推移閉包が作成され、これらの依存関係はすべて既知として扱われます。Windows のバージョンによっては、この推移閉包が作成されないものもあります。このようなバージョンでは、明示的に既知としてリストされている DLL だけが既知の DLL として扱われます。あるバージョンの Windows では、既知の DLL はシステムの起動時にカーネルによって事前に読み込まれます。他のバージョンでは、このような事前読み込みを行わずに、カーネルは DLL のパスを検索するという手間を省くためだけに、既知の DLL のリストを使用します。

バージョンごとに異なるのは、既知の DLL のリストの解釈だけではありません。KnownDLLs レジストリ キーの内容も異なることがあります。Windows パフォーマンス チームは、既知の DLL のリストだけでなく、アプリケーションが Windows をどのように使用するかを把握して、リストが一連の DLL に変換されるときに使用される規則も変更しています。これは、エンジニアリングではいつも行われることですが、トレードオフという 1 つのゲームです。既知の DLL をシステムの起動時に事前に読み込んでおけば、それらの DLL を使用するアプリケーションの起動は高速になりますが、そこには代償を伴います。つまり、それらの DLL が実際に使用されるかどうかにかかわらずメモリに残るため、システムの起動に時間がかかり、メモリの使用量が増加することになります。これは、他を犠牲にしてでも一部のコンポーネントのパフォーマンスを向上させるというゲームです。適切なバランスをとることは困難な作業です。また、おわかりのように、このバランスは使用パターンが進化するたびに絶えず調整されることになります。

あまり明らかにはされていない既知の DLL の結果として、既知の DLL はローカルにリダイレクトされる DLL よりも優先されるという点があります (ローカルにリダイレクトされる DLL については、2007 年 1 月号のこのコラムで説明しました)。考えてみると、これは思いがけない動作ではなく、実際に予測される動作であることがわかるでしょう。結局のところ、既知の DLL のリストの目的は、検索パスを省略し、DLL の読み込み速度を上げることです。カーネルがローカルにリダイレクトされる DLL を確認する必要があれば、DLL の読み込み速度が遅くなるだけです。検索パスにたった 1 つのディレクトリを追加することはそれほど大変なことではないと考えるかもしれませんが、その 1 つのディレクトリが地球の真中にあるネットワーク サーバーだとすると、1 つのディレクトリを追加しただけで、パフォーマンスが大幅に低下することもありえます。

信じられないかもしれませんが、既知の DLL のリストに含まれる特定の DLL に依存するプログラムに出会いました。このプログラムは、アプリケーション ディレクトリに Version.dll というファイルを保持していました。通常の規則に基づくと、この Version.dll のプライベート コピーはシステム ディレクトリにある Version.dll よりも優先されますが、Windows XP では、Version.dll が既知の DLL としてリストされています。つまり、アプリケーション ディレクトリにあるコピーは無視され、システム ディレクトリ内のバージョンが使用されます。

Windows Vista® では、Version.dll は既知の DLL としてリストされません。これは、パフォーマンス チームのメンバが、コストを十分に正当化できるほど、アプリケーションが Version.dll を使用していないと判断したためと考えられます。その結果、実際にアプリケーションが依存するのはカーネル上の DLL であり、プログラムが自身のアプリケーション ディレクトリにインストールした DLL は無視されるため、このプログラムは Windows Vista で機能しなくなります。プログラムは意図的に検索パスに DLL をインストールしていましたが、Windows に依存することで、その DLL が無視されたのです。間違いなく Windows にファイルを無視させる必要があるのなら、最初にファイルをインストールしない方がもっと効率的なメカニズムです。意外だったのは、プログラムを作成した会社が、セキュリティ ホールが見つかったと主張して、バグを届け出たことです。

Raymond Chen は自分の Web サイト「The Old New Thing」および同じタイトルの書籍 (Addison-Wesley、2007 年) で、Windows の歴史と Win32 プログラミングについて扱っています。彼の T シャツのサイズについてはわかりませんが。

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; 許可なしに一部または全体を複製することは禁止されています.