Windows CE .NET の高度なメモリ管理

Douglas Boling、Windows Embedded MVP
Boling Consulting

August 2002

適用対象:
    Microsoft® Windows® CE .NET
    Microsoft Windows CE 3.0
    Pocket PC 2002

目次

要約
メモリ領域の範囲内でやりくりする
DLL の読み込みの問題

要約

Microsoft Windows CE の利点の 1 つは、Microsoft Win32® アプリケーション プログラミング インターフェイス (API) をサポートするということです。数十万人もの Windows プログラマは、Win32 API と MFC の知識を活用して、比較的スムーズに Windows CE に移行できます。Windows CE は、Win32 API のサブセットを実装できます。ただし、Windows CE は、Windows XP とは要件も実装方法も異なるまったく別のオペレーティング システムであることを忘れないでください。Windows CE による Win32 互換機能の実装方法を理解していれば、アプリケーションの設計や問題の診断に大いに役立ちます。

メモリ管理は、Windows CE と Windows XP の実装方法の違いが最も顕著に現れる部分の 1 つです。Windows CE は、旧式のグローバル ヒープ関数を除くほぼすべての Win32 メモリ管理関数をサポートしますが、これらのメモリ管理 API は実装方法がまったく異なります。これらの違いは、Windows CE と Windows デスクトップ バージョンの微妙な違いをよく理解していないプログラマの作業の妨げとなる可能性があります。これらの問題を理解するには、まず、Windows CE でメモリがどのように管理されているかを理解する必要があります。

システム メモリのマップ

Windows XP と Windows CE はどちらも 32 ビット オペレーティング システムであり、4 GB の仮想アドレス空間をサポートします。Windows XP では、アドレス空間が 2 つの 2 GB 領域に分けられています。アドレス空間の上半分は、システム用に予約されています。下の 2 GB のアドレス空間は、実行中の各アプリケーション用に複製されます。

図 1. Windows XP の仮想メモリ空間

一見すると、Windows CE の仮想アドレス空間の編成はシステムの予約領域と複製されるアプリケーション空間を持ち、Windows XP に類似しています。図 2 は、Windows CE のアドレス空間を示しています。この場合も、上半分の 2 GB のアドレス空間はシステム用に予約されています。下半分のアドレス空間は、多数の領域に分割されています。この領域の大部分 (ほぼ半分) は、" ラージメモリ領域" として定義されています。この領域は通常、メモリ マップ ファイルのための大きいメモリ空間ブロックの割り当てに使用されます。

"ラージメモリ領域" の下には、この記事では "予約済み" と呼んでいるもう 1 つの大きな領域があります。この "予約済み" 領域の下には、メモリ空間の最下位である 64 MB の領域があります。この 64 MB の領域 (正確には、この領域の最下位の 32 MB) は、実行中の各アプリケーション用に複製されます。

図 2. Windows CE の仮想メモリ空間

Windows CE アプリケーション メモリのマップ

仮想アドレス空間の最下位 64 MB には、Windows CE アプリケーションがあります。図 3 は、アプリケーションの仮想アドレス空間を示しています。アプリケーション コードは、Windows XP アプリケーションと同様に、仮想アドレス 0x10000 から読み込みが開始されます。アプリケーションを起動すると、すべてのコードに十分な領域がアドレス空間に予約されます。実際のコードは、オンデマンドのページング機能によって、必要に応じてアドレス空間内へ読み込まれます。

コード用に予約された領域の上に、読み取り専用および読み取り/書き込み静的データ領域用のページが予約されます。さらに、ローカル ヒープの領域と、アプリケーションで実行中の各スレッドのスタック領域が予約されます。各スタック領域の予約サイズは、スレッドの起動時に固定されます。実際の RAM は、スタックのサイズの増加に応じてコミットされます。これに対して、ヒープの予約領域は、RAM ブロックがヒープに割り当てられたときに、必要に応じて拡張できます。

インプレース実行 (XIP) DLL の読み込みは、64 MB 空間の最上部から下方に向けて行われます。ROM の作成時に、各 XIP DLL のベース アドレスが設定されます (つまり、アドレス空間内に XIP DLL が配置される)。XIP でない DLL を読み込んだ場合は、32 MB 境界の下に配置されます。XIP でない DLL は、RAM ベースの DLL とも呼ばれ、ROM から取り出して解凍されてオブジェクト ストアから読み込まれるか、コンパクト フラッシュ カードなどの外部ファイル システムから読み込まれます。アプリケーションの仮想メモリ空間の上位 32 MB は、XIP DLL 専用の空間です。

図 3. Windows CE .NET アプリケーションの仮想メモリ空間

別のヒープの作成または VirtualAlloc API の直接呼び出しのいずれかによって、アプリケーションで追加のメモリが割り当てられる場合は、アプリケーション空間の最下部から検索して最初に見つかった十分な大きさの空き領域が使用されます。

メモリ領域の範囲内でやりくりする

Windows CE アプリケーションの制約の 1 つは、アプリケーションの使用可能な RAM 容量であり、もう 1 つの重要な制約は、アプリケーションの仮想アドレス空間が 32 MB という比較的小さな空間であることです。XIP DLL は 32 MB より上の空間に読み込まれますが、他のすべてのメモリ割り当ておよび RAM ベースの DLL は、アプリケーションの 32 MB のメモリ空間に収まる必要があります。Windows CE プログラマにとって、この 32 MB の "メモリ領域" は、問題というよりは克服する課題であると言えます。

この一見して大きなメモリ空間がどのような制限要因となるかを理解するには、VirtualAlloc API の操作を理解する必要があります。VirtualAlloc は、すべての Microsoft Win32 オペレーティング システムのメモリ割り当てに使用される最も基本的な呼び出しです。この関数は、ページ レベルでメモリを割り当てます。ページは、CPU によって割り当てまたは解放可能なメモリの最小単位です。Windows CE .NET CPU のページ サイズは、それぞれの CPU に応じて、1024 バイトか 4096 バイトのいずれかです。最もよく使用されるページ サイズは 4 KB です。

VirtualAlloc 呼び出しは、2 ステップでメモリを割り当てます。最初に、仮想メモリ空間の領域を予約します。この予約によって RAM が消費されることはありません。他の理由のために使用されないように仮想アドレス空間の一部を予約するだけです。メモリ空間が予約されたら、領域の一部または全体を "コミット" して、実際の物理メモリを予約領域にマップできます。VirtualAlloc 関数は、メモリ空間の予約およびメモリのコミットのどちらにも使用されます。VirtualAlloc 関数のプロトタイプを次に示します。

LPVOID VirtualAlloc (LPVOID lpAddress, DWORD dwSize,
                     DWORD flAllocationType,
                     DWORD flProtect);

VirtualAlloc の最初のパラメータには、割り当てるメモリ領域の仮想アドレスを指定します。前に予約したメモリ ブロックを VirtualAlloc でコミットするときに、lpAddress パラメータを使用して予約済みのメモリ ブロックを識別します。このパラメータが NULL の場合、メモリ領域を割り当てる位置はシステムによって決定され、64 KB 境界に丸められます。2 番目のパラメータの dwSize には、割り当て領域または予約領域のサイズを指定します。このパラメータは、ページ数ではなくバイト数で指定するため、要求したサイズは次のページ境界に切り上げられます。

flAllocationType パラメータは、割り当ての種類を指定します。MEM_COMMIT、MEM_AUTO_COMMIT、MEM_RESERVE の各フラグを組み合わせて指定できます。MEM_COMMIT フラグは、プログラムが使用するメモリを割り当てます。MEM_RESERVE は、後でコミットする仮想アドレス空間を予約します。予約したページにアクセスするには、その領域を指定し、MEM_COMMIT フラグを使用して、もう一度 VirtualAlloc を呼び出す必要があります。MEM_AUTO_COMMIT フラグは、Windows CE 独自のたいへん便利な機能ですが、この記事で取り上げません。

結果として、使用可能な RAM を VirtualAlloc によって割り当てるには、最初の呼び出しでメモリ空間を予約し、2 回目の呼び出しで物理 RAM をコミットするために VirtualAlloc を 2 回呼び出す方法と、flAllocationType パラメータに MEM_RESERVE フラグと MEM_COMMIT フラグの両方を指定して VirtualAlloc を 1 回だけ呼び出す方法があります。

予約フラグとコミット フラグを合わせて使用すると、短いコードで迅速かつ簡単にメモリを割り当てることができます。この技法は Windows XP アプリケーションでよく使用されますが、Windows CE アプリケーションでは好ましい技法ではありません。次のコードは、この問題を表しています。

INT i;
PVOID pMem[512];

for (i = 0; i < 512; i++) {
   pMem[i] = VirtualAlloc (0, PAGE_SIZE, MEM_RESERVE | MEM_COMMIT,
                           PAGE_READWRITE);
}

このコードは問題がないように見えます。このコードは、各ブロックのサイズを 1 ページとして、512 個のメモリ ブロックを割り当てます。問題は、Windows CE システムでこのコードを実行すると、RAM に数 MB の空きがあるシステムの場合でも常に失敗することです。これは Win32 オペレーティング システムでのメモリ領域の予約方法の問題です。

Windows CE .NET を含むすべての Win32 オペレーティング システムでは、仮想メモリ空間の領域を予約する場合に、64 KB 境界に予約領域を配置します。したがって、上記のコードは、それぞれが 64 KB 境界に配置された 512 個の領域の予約を試みます。Windows CE アプリケーションで問題となるのは、32 MB の仮想メモリ空間の範囲内に予約領域を配置しなければならないことです。アプリケーションのメモリ空間全体のうち、この仮想空間には 512 個の 64 KB 境界しかありませんが、アプリケーションのメモリ空間の一部は、アプリケーション コード、ローカル ヒープ、アプリケーションが読み込む DLL の領域として必要になります。通常、上記のコードは、VirtualAlloc をおよそ 470 回呼び出した後に失敗します。

この問題の解決策は、すべての割り当てに必要な領域を最初に予約し、後から必要に応じて RAM をコミットすることです。次のコードは、この解決策を表しています。

INT i;
PVOID pBase, pMem[512];

pBase = VirtualAlloc (0, 512*PAGE_SIZE, MEM_RESERVE, PAGE_READWRITE);

for (i = 0; i < 512; i++) {
   pMem[i] = VirtualAlloc (pBase + (i * PAGE_SIZE), PAGE_SIZE,
                           MEM_COMMIT, PAGE_READWRITE);
}

この問題について理解しておくと、問題を避ける手掛かりになります。512 個の領域に制限された Windows CE アプリケーションのアドレス空間の問題は、アプリケーションのさまざまな部分に影響を及ぼします。ここで取り上げた問題は、ほんの一部にすぎません。

大きいメモリ ブロックを割り当てる

もう 1 つの問題は、Windows CE .NET アプリケーションの 32 MB アドレス空間の範囲内に、非常に大きいメモリ ブロックを割り当てる方法です。特定のニーズを満たすために 8 MB、16 MB、または 32 MB の RAM ブロックが必要な場合に、アプリケーションのアドレス空間全体が 32 MB に制限されているときは、どのような方法でこのメモリを割り当てることが可能でしょうか。解決策は、以前のバージョンの Windows CE .NET でビデオ ドライバに対して使用していた方法を適用することです。この方法を適用すると、Windows CE .NET で 2 MB を超えるアドレス空間を予約する VirtualAlloc の呼び出しが検出されたときに、そのアドレス空間は 32 MB ボックス内に予約されません。その代わりに、このブロックは、2 GB のシステム予約領域のすぐ下にある、グローバル メモリ空間に配置された "ラージメモリ領域" 内に予約されます。

メモリ空間が予約されると、VirtualAlloc を呼び出して、予約された空間内の特定のページをコミットできます。この方法を使用すると、32 MB ボックスという制約を課せられても、非常に大きいメモリ ブロックをアプリケーションで使用できるようになります。次のコードは、64 MB ブロックを割り当てた後、予約領域の 1 ページをコミットする方法を示しています。

   PVOID ptrVirt, ptrMem;
   ptrVirt = VirtualAlloc (0, 1024 * 1024 * 64, MEM_RESERVE,
                        PAGE_NOACCESS);
   if (!ptrVirt) return 0;

   ptrMem = VirtualAlloc ((PVOID)((int)ptrVirt+4096),
                          4096, MEM_COMMIT, PAGE_READWRITE);
   if (!ptrMem) {
      VirtualFree (ptr, 0, MEM_RELEASE);
      return 0;
   }
   return ptrMem;

また、このコードは仮想メモリ API に直接関連のある特徴の 1 つを示しています。それは、RAM を大量に消費せずに大規模なスパース配列を作成できるということです。上のコードで予約された 64 MB 領域は、物理 RAM をまったく消費しません。この例では、VirtualAlloc の 2 回目の呼び出しでページがコミットされたときに、1 ページに相当する 4096 バイトの RAM が消費されるだけです。

DLL の読み込みの問題

現在では多数の Windows CE プログラマが、Pocket PC 2002 でプログラミングを行っています。Windows CE .NET メモリ アーキテクチャの変更による修正にもかかわらず、アプリケーションの DLL 読み込みに関して、Pocket PC 2002 プログラマに影響を与える重大な問題があります。この問題を理解するには、まず Windows CE .NET と Windows CE 3.0 の主な相違点の 1 つを理解し、これらのバージョンの Windows CE で、DLL がどのように読み込まれ、管理されているかを認識しておく必要があります。

Windows CE .NET の新機能の 1 つは、アプリケーションの仮想アドレス空間が、以前のバージョンの Windows CE の 32 MB から 64 MB に拡張されたことです。XIP DLL に使用できる上位 32 MB の仮想空間は、Windows CE 3.0 には用意されていません。そのため、Windows CE 3.0 ベースのシステムで実行しているアプリケーションの XIP DLL、コード、およびすべてのデータを 32 MB の仮想アドレス空間に読み込む必要があります。図 4 は、Windows CE 3.0 アプリケーションのメモリ空間を示しています。

図 4. Windows CE 3.0 アプリケーションの仮想メモリ空間

Pocket PC 2002 は Windows CE 3.0 がベースになっているため、仮想メモリ空間の制限は、そのプラットフォームで実行しているアプリケーションに適用されます。

DLL を読み込む

XIP DLL を読み込む Windows CE .NET 上の追加の 32 MB の空間を除いて、Windows CE が DLL の読み込みに使用する技法は、Windows CE .NET および以前のバージョンの Windows CE と同じです。

DLL の読み込みが要求されると、以前にその DLL が別のアプリケーションによって読み込まれていないかどうかの確認が行われます。同じ DLL が読み込まれていないこと、および XIP DLL でないことが確認されると、改良されたトップダウン検索によって、32 MB の仮想メモリ マップにある最初の使用可能な空間が検出されます。改良された検索として見なされる理由は、現在のプロセスによって DLL が読み込まれない場合でも、別の DLL で使用されているアドレスが回避されるようになったからです。この検索技法では、システム内のすべての DLL が重複しない一意のアドレスに読み込まれます。

一意のアドレスが必要な理由は、DLL が複数のプロセスによって読み込まれたときに、すべてのプロセスで同じ仮想アドレスに配置されるようにするためです。複数の DLL を一意のアドレスにそれぞれ読み込むと、以前に別のプロセスによって読み込まれた DLL をアプリケーションで読み込む必要が生じた場合に、他のプロセスでその DLL がマップされた仮想アドレスを、DLL を要求しているプロセスで利用できるようになります。図 5 は、複数の DLL をそれぞれ読み込む 3 つのプロセスを示しています。この図では、DLL A は 3 つのすべてのプロセスで同じアドレスに読み込まれています。プロセス 2 は、DLL C を読み込んでいます。DLL C は、プロセス 1 で読み込まれた DLL B と DLL A よりも下位のアドレス空間に読み込まれます。後から、プロセス 3 で DLL A と DLL D を読み込みます。どのプロセスでも、同じ DLL は同一のアドレスに読み込まれ、異なる DLL はそれぞれの一意のアドレスに読み込まれていることに注目してください。

図 5. 複数の DLL を読み込む 3 つのプロセス

ここで、起こり得る問題について検討してみましょう。たとえば、図 6 で示すように、プロセス 2 でたいへん大きな DLL C を読み込んだとします。プロセス 3 は、それ自体が大きな .exe ファイルでありながら、プロセス 2 で非常に大きな DLL C を読み込んだ後に DLL を読み込むという不運が重なりました。明らかに、プロセス 3 はトラブル寸前の状態にあり、他のプロセスで読み込まれていない DLL の読み込みを試みると問題が生じます。この例には、いくつかの不自然な点があります。この問題が発生するには、DLL C のサイズが桁外れに大きいか、プロセス 2 で多数の DLL を読み込む必要がありますが、これが自然に発生するとは考えにくいからです。

図 6. 3 つのプロセスによる複数の DLL の読み込みとプロセス 2 による非常に大きな DLL の読み込み

ここでは、通常の DLL の読み込みという観点から、XIP DLL と XIP でない DLL を取り扱った複雑な問題について説明します。OEM によって ROM イメージが作成されるときは、各 XIP DLL のベース アドレスが一意のアドレスに設定されます。この方法により、アドレスが衝突することなく、すべての XIP DLL を読み込むことが可能になります。これらは XIP であるため、いずれかのアプリケーションが DLL コードを要求した場合は、DLL コードが含まれる ROM をアプリケーションの仮想アドレス空間に直接マップできます。プロセスで XIP DLL を読み込むときは、XIP DLL のベース アドレスを別のアドレスに再設定することはできません。ベース アドレスを変更すると、それに伴って読み取り専用コードの修正が必要になるためです。

XIP でない DLL に使用可能な空き仮想アドレスを検索するときに、カーネルは最下位の XIP DLL より下のアドレスから検索を開始します。この最下位の XIP DLL は、使用しているアプリケーションが読み込んだものではありません。特定のアプリケーションによって読み込まれた XIP DLL かどうかにかかわらず、システム全体にわたって最下位の XIP DLL です。前に説明したように、この技法によって、現在読み込まれているすべての DLL が、他のプロセスで読み込み可能になります。この方法はたいへん有効ですが、Pocket PC 2002 の Windows CE 3.0 の実装方法は独特であるため、DLL が読み込まれない場合もあります。

Pocket PC 2002 の Windows CE 3.0 の実装では、デバイス上で複数の ROM を使用できるという Windows CE 3.0 の機能を巧みに利用しています。この機能により、複数の ROM に連続した物理アドレスがない場合でも、システムでそれらの ROM を使用できます。

前に説明したように、DLL を XIP にするには、特別な処理が必要です。DLL のベース アドレスを設定するには DLL コードの変更が必要であるため、ROM イメージの作成時に設定する必要があります。最初の ROM の作成時に、ROM 作成ツールによって、ROM 内の他の DLL と重複しないように各 DLL のベース アドレスが設定されます。

複数の XIP 領域の使用は、カーネル設計者が DLL の読み込みの問題を再検討する必要があることを意味します。複数の XIP 領域システムで XIP DLL が重複しないようにするには、2 番目の ROM 内の DLL のベース アドレスを最初の ROM イメージの最下位の DLL よりも下位の仮想アドレスに設定する必要があります。さらに他の ROM を使用する場合は、それらの XIP 領域で DLL のベース アドレスを前の ROM よりも下位に設定する必要があります。

複数の ROM イメージの使用は、さまざまな理由で役立ちます。OEM または Microsoft で Windows CE イメージの一部を更新する必要が生じた場合は、システム全体ではなく特定の ROM だけを更新できます。他の ROM に影響を与えずに 1 つの ROM を更新するには、下位のイメージにある DLL のベース アドレスを、前のイメージの最下位の DLL のアドレスに設定するのではなく、それよりもさらに下位のアドレスに設定して、人為的に DLL のセット間に仮想メモリ ギャップを生じさせることをお勧めします。

Windows CE 3.0 をベースにした Pocket PC 2002 を担当している Microsoft の開発者は、複数の XIP 領域の利点を十分に利用しました。Pocket PC のほとんどの実装には、5 個以上の XIP 領域があります。問題は、領域間のギャップが大きすぎることです。一般に、Pocket PC 2002 イメージの最下位の XIP DLL は、0x0100000 より下位にベース アドレスが設定されています。Windows CE では、RAM ベースの DLL が最下位の XIP DLL より下位に配置されるため、RAM ベースの DLL、アプリケーション コード、ヒープ、およびスタックに使用できる空間は、32 MB の仮想アドレス空間に制限されているというよりは、最下位の XIP DLL より下位の 16 MB 未満の空間に制限されます。

図 7 は、Pocket PC 2002 の問題を示しています。仮想メモリ空間の XIP DLL のための領域がかなり大きいことに注目してください。実際には、この図はかなり控えめに描かれています。通常、Pocket PC 2002 では、仮想メモリ空間の半分以上を XIP 領域が占めています。RAM ベースの DLL A、B、C、D の読み込みは、仮想アドレス空間のかなり下位で発生している点に注目してください。

図 7. 仮想アドレス空間の大きな部分が XIP DLL によって使用された Pocket PC 2002 での DLL の読み込み

企業アプリケーションが大量のデータを処理するため、企業の開発者は Windows CE アプリケーションで大規模データベースの使用を余儀なくされました。通常、データベース エンジンは DLL として実装され、ほとんどが大容量です。上の例で、データベース DLL はトラブルメーカーである DLL C に相当します。Pocket PC 2002 アプリケーションの使用可能な仮想メモリ空間が 16 MB 未満でありながら、その一方で大規模な RAM ベースの DLL が必要になると、多くの開発者は空間不足のために開発したアプリケーションを実行できないことに気付きました。不足しているのは RAM ではなく、仮想メモリ空間です。

DLL を結合する

この Pocket PC 2002 の問題は、さまざまな技法によって改善できます。第一に、開発者は複数の小さな DLL を大きな DLL にまとめる必要があります。各 DLL は、少なくとも 1 つの 64 KB の領域を占めます。サイズが 20 KB の DLL を 4 つ使用するアプリケーションでは、合計で 256 KB のメモリ空間を消費します。4 つの DLL を 1 つの大きな DLL に結合すれば、消費する仮想メモリ空間は 64 KB だけで済みます。この場合、コードのサイズは 60 KB ですが、最小のフットプリントは 64 KB です。原則として、1 つの DLL のサイズが 64 KB 以下になるように DLL を結合してください。多数の小さな DLL を使用するアプリケーションでは、いくつかの大きな DLL に結合するだけで、DLL の読み込みの問題が解決する場合もあります。

DLL コードをアプリケーションの中に移動する

Pocket PC 2002 における DLL の問題を改善するもう 1 つの方法は、DLL のコードをアプリケーションの中に移動することです。複数のプロセスで共用するコードの場合でも、他のアプリケーションとは無関係にそれぞれのプロセスが DLL を読み込むため、プロセスごとにコードを 1 つずつ用意したほうが有利なこともあります。

最初は、コードをアプリケーションの中に移動しても問題は改善されないように思えます。なぜなら、コードはアプリケーションの 32 MB の仮想空間内に存在し続けるからです。しかし、ここで重要なのは、大きな RAM ベースの DLL を必要としない大きなアプリケーションと、RAM ベースの DLL を読み込んで使用する小さなアプリケーションを作成することです。この技法では、大きなアプリケーションがほとんどのビジネス ロジックを実行し、小さなアプリケーションが大きな DLL を読み込みます。大きなアプリケーションで、大きな DLL のサービスが必要になった場合は、プロセス間通信を使用して、小さなプロセスが DLL を呼び出し、再びプロセス間通信を使用して大きなプロセスにデータを返します。

DLL の読み込み順序を定義する

DLL 数の減少やアプリケーションのコードの中継では不十分な場合は、抜本的な改善策が必要になります。それは、手動で DLL の読み込み順序を指定することです。大きな DLL を最初に読み込むと、後続のすべての小さな DLL の読み込みアドレスが下位に移行されるため、読み込み順序は重要です。通常、大きな DLL は単一のアプリケーションによって使用されます。しかし、大きな DLL を最初に読み込むと、他のアプリケーションの DLL の読み込みアドレスが下位に移行されて、読み込みができなくなる場合もあります。

この問題を解決するには、最初に小さな DLL を読み込み、面倒な大きな DLL は後に回すか、一番最後にします。ここで問題になるのは、DLL の読み込み順序を指定する方法です。1 つの方法として、アプリケーションの個々のプロセスの起動順序を指定できますが、この方法では問題が生じる可能性があります。

DLL の読み込み順序を定義するもう 1 つの方法は、Win32 の LoadLibrary 関数を繰り返し呼び出して RAM ベースの DLL を定義された順序で読み込む小さなアプリケーションを記述することです。最初にこのアプリケーションを実行してから主アプリケーションを実行します。DLL 読み込みプログラムは、主アプリケーションが終了するまで実行された後に終了します。また、CreateProcess を呼び出して主アプリケーションを起動し、CreateProcess から返されるプロセス ハンドルをブロックして、主アプリケーションが終了するのを待機することもできます。読み込んだ DLL は、結果的に他のプロセスによってすべて読み込まれるため、DLL 読み込みアプリケーションは大量の RAM を消費しません。

Pocket PC 2002 における DLL の読み込みの問題の解決策は、どれも骨の折れる作業ばかりです。洗練された方法はなく、保守にも手間がかかります。しかし、開発者はこれらの解決策を使用して製品を開発しています。この問題は Pocket PC の今後のリリースで解決される予定ですが、Pocket PC 2002 の製品の開発者は、臨機応変な対応を行うことが重要です。

Windows CE のメモリ管理について理解していれば、開発者は危険を避けてすばやく問題を診断できます。また、Windows CE による DLL の管理方法を理解していれば、Pocket PC 2002 アプリケーションで起こり得る問題を回避するのに役立ちます。Pocket PC の今後のリリースでこの問題が解決された場合でも、既に現場で使用されている何百万台ものデバイスのアプリケーションが必要です。問題を探す場所について理解しておくことが、問題の発見と解決の第一歩です。