Microsoft公式解説:DLLが正式にアンロードされていないのにメモリから消える問題の要点

Microsoft が 2026年6月26日に公開した「The case of the DLL that was not present in memory despite not being formally unloaded, part 2」は、新機能の追加や設定変更の告知ではなく、Windows アプリケーションのクラッシュ解析に関する技術記事です。結論から言うと、管理者がすぐに変更すべき Microsoft 365 や Azure の設定、移行期限、グローバル展開スケジュールは示されていません。

ただし、Windows 上で動作する業務アプリ、常駐アプリ、C++ 製アプリ、DLL を明示的に読み込むアプリを運用している組織にとっては重要です。今回の記事は、「正式にアンロードされていないはずの DLL がメモリ上に存在しない」という一見不可解なクラッシュが、実はメモリ破損によって別の形で表面化した可能性を示しています。特に、アプリ終了時のクラッシュを「利用者影響が小さい」と見過ごしている場合は、ログ収集やクラッシュダンプの確認方針を見直す価値があります。(Microsoft for Developers)

目次

Microsoft の「The case of the DLL that was not present in memory despite not being formally unloaded, part 2」で確認すべきポイント

今回の Microsoft 公式情報は、The Old New Thing に掲載された Raymond Chen 氏の記事です。主題は「Tying two bugs together」、つまり別々に見えていたクラッシュ事象を、同じ根本原因に結び付けて考えるというものです。

記事で扱われているのは、次のような現象です。

あるプロセスで、DLL が正式にはアンロードされていないように見えるにもかかわらず、実際にはメモリからマップ解除されており、その DLL 内のコードを呼び出そうとしてクラッシュする。さらに別のクラッシュでは、データ構造の一部に 01 という 1 バイトが書き込まれて破損している。Microsoft の記事では、この 2つの現象が同じメモリ破損バグの別表現だった可能性を説明しています。(Microsoft for Developers)

重要なのは、これは Windows の一般利用者向けの更新通知ではなく、開発者・運用担当者向けの障害解析ノートに近い内容だという点です。したがって「どの設定を有効化すればよいか」ではなく、「自社アプリやサードパーティ製アプリで似たクラッシュが起きたときに、どこを疑うべきか」を読み取る記事です。

今回の更新は新機能ではなく、DLL とメモリ破損の解析記事

今回の公式記事から読み取れる更新ポイントを、実務目線で整理すると次の通りです。

項目内容
公開日2026年6月26日
対象Windows アプリケーション開発者、デスクトップアプリ運用担当者、障害解析担当者
主なテーマDLL が正式にアンロードされていないように見えるのに、実際にはメモリ上から消えているクラッシュの解析
直接の製品変更記事内では確認されていない
管理センターの設定変更記事内では示されていない
移行期限記事内では示されていない
管理者が見るべき点アプリ終了時クラッシュ、メモリ破損、DLL のロード・アンロード処理、サードパーティ製アプリの安定性

Microsoft 365 管理センター、Azure ポータル、Intune、Defender、Entra ID などで何かを設定変更するタイプの情報ではありません。むしろ、Windows 上で業務アプリを運用する組織が、クラッシュ調査やベンダー問い合わせの際に参照すべき技術的なヒントと捉えるのが適切です。

何が起きていたのか:正式にアンロードされていない DLL が消える仕組み

今回の記事の中心は、HMODULE の下位ビットと、LOAD_LIBRARY_AS_DATAFILE による DLL の扱いです。

Microsoft Learn によると、LoadLibraryEx は DLL を通常の実行可能モジュールとして読み込むだけでなく、リソース取得などを目的として「データファイル」として読み込むことができます。LOAD_LIBRARY_AS_DATAFILE などで読み込まれた場合、DLL は通常の実行用 DLL とは異なる扱いになり、関数呼び出しの対象として使う前提ではありません。(Microsoft Learn)

今回の記事では、どこかの処理が本来書き込んではいけない場所に 01 という 1 バイトを書き込んでいたことが手掛かりになっています。HMODULE の下位ビットは、データファイルとして読み込まれたモジュールを識別するために使われます。もし既存の HMODULE の下位バイトが誤って 01 に書き換わると、本来は通常の DLL ハンドルだったものが、データファイル用のハンドルのように見えてしまいます。(Microsoft for Developers)

その状態でプロセス終了時のクリーンアップ処理が FreeLibrary を呼び出すと、システム側は「これはデータファイルとして読み込まれたモジュールだ」と解釈し、通常の DLL アンロードとは異なる処理でメモリマッピングを解除します。結果として、DLL の管理リスト上では存在しているように見えるのに、実際のメモリ上には存在しないという矛盾した状態が生まれます。(Microsoft for Developers)

通常の DLL とデータファイルとして読み込まれた DLL の違い

障害調査で混乱しやすいポイントは、「DLL が読み込まれている」という言葉が常に同じ意味ではないことです。

読み込み方主な目的典型的な用途注意点
通常の DLL として読み込みコード実行関数呼び出し、プラグイン読み込み参照カウントや DllMain の動作を意識する必要がある
データファイルとして読み込みリソース参照メッセージ、アイコン、文字列リソースの取得実行用 DLL として扱えないケースがある
イメージリソースとして読み込みPE 形式のリソース参照リソース取得の最適化通常の DLL ロードとは管理方法が異なる

Microsoft Learn では、LOAD_LIBRARY_AS_DATAFILE を使用した場合、ファイルはデータファイルのように仮想アドレス空間へマップされ、実行準備は行われないと説明されています。また、この方法で読み込まれた DLL は GetProcAddress などの通常の関数解決用途には使えません。(Microsoft Learn)

この違いを理解していないと、クラッシュダンプ上で「DLL はロード済みのはずなのに、なぜコードが存在しないのか」という誤った方向に調査が進みやすくなります。

影響範囲:Microsoft クラウド設定ではなく Windows アプリ運用が中心

今回の情報の影響範囲は、Microsoft 365 や Azure のテナント全体に対する設定変更ではありません。対象になるのは、Windows 上で動くアプリケーションの設計、実装、運用監視です。

特に注意したいのは、次のような環境です。

対象確認すべき理由
C++ 製のデスクトップアプリLoadLibraryLoadLibraryExFreeLibrary を直接扱っている可能性がある
プラグイン機構を持つ業務アプリDLL のロード・アンロード順序が複雑になりやすい
常駐アプリ、エージェント、監視ツール長時間稼働後の終了処理で問題が表面化しやすい
サードパーティ製アプリを多数導入している端末自社でコードを修正できず、ベンダー調査が必要になる
終了時クラッシュを無視している運用ユーザー影響が小さく見えても、根本にメモリ破損がある可能性がある

Microsoft の記事でも、問題がプロセス終了時に発生していたため、長く見過ごされていた可能性に触れています。アプリ終了時のクラッシュは、ユーザーが作業を終えた後に発生するため業務影響が目立ちにくい一方で、内部的には重大なメモリ破損を示している場合があります。(Microsoft for Developers)

設定変更と移行期限はあるのか

今回の公式情報では、管理者が実施すべき設定変更や移行期限は示されていません。ここは誤解しやすいので、明確に切り分ける必要があります。

確認項目今回の扱い
Microsoft 365 管理センターでの設定変更なし
Azure 側の構成変更なし
Windows Update の適用期限記事内では示されていない
API 廃止や移行期限記事内では示されていない
開発者向けの注意喚起あり
クラッシュ調査時の着眼点あり

ただし、設定変更がないからといって、運用上の対応が不要という意味ではありません。自社で Windows アプリを開発している場合や、業務端末でクラッシュが増えている場合は、今回の記事を「調査観点の追加」として扱うべきです。

管理者が確認すべきポイント

管理者や運用担当者は、ソースコードの細部まで追わなくても、次の観点を押さえておくと実務で役立ちます。

アプリ終了時のクラッシュを軽視しない

アプリ終了時のクラッシュは、ユーザーから見ると「作業は終わっているから問題ない」と判断されがちです。しかし、終了処理では DLL、スレッド、ファイルハンドル、ログ出力、プラグイン解放などが一気に行われます。ここで発生するクラッシュは、単なる終了時の後始末ではなく、以前から存在していたメモリ破損が最後に表面化したものかもしれません。

実務では、次のように扱うとよいでしょう。

状況推奨対応
特定アプリだけが終了時に落ちるアプリ名、バージョン、発生端末、発生タイミングを記録する
複数モジュールで似たクラッシュが出るそれぞれ別問題と決めつけず、共通するメモリ破損を疑う
ユーザー影響が少ないため放置しているダンプ取得を有効化し、再現頻度と影響範囲を確認する
更新後にクラッシュが増えたOS 更新、アプリ更新、セキュリティ製品更新の時系列を整理する

DLL のロード・アンロード処理を棚卸しする

自社開発アプリがある場合は、LoadLibraryLoadLibraryExFreeLibraryGetModuleHandle などを使っている箇所を確認します。特に、RAII で HMODULE を自動解放している場合、ハンドルの所有権が曖昧だと終了時に問題が出る可能性があります。

Microsoft Learn では、FreeLibrary は DLL の参照カウントを減らし、参照カウントがゼロになるとプロセスのアドレス空間からモジュールをアンロードすると説明されています。また、GetModuleHandle が返すハンドルは参照カウントを増やさないため、そのハンドルを FreeLibrary に渡すと DLL が早期にアンロードされる可能性があると注意されています。(Microsoft Learn)

確認時は、次のような観点でコードレビューすると効果的です。

確認ポイント悪い例望ましい考え方
ハンドルの所有権どこで取得した HMODULE か分からないLoadLibrary で取得したものだけを解放対象にする
GetModuleHandle の扱い取得したハンドルをそのまま FreeLibrary に渡す参照カウントを増やさないハンドルとして扱う
データファイル読み込みリソース取得用のハンドルを実行用 DLL と同じように扱う用途ごとにハンドル管理を分ける
終了処理グローバルデストラクタや終了時処理に任せきり明示的な終了順序を設計する

サードパーティ製アプリはベンダーに「終了時クラッシュ」としてではなく「メモリ破損疑い」として伝える

今回の記事では、根本的なメモリ破損の原因は記事執筆時点で特定されていないとされています。また、現象が特定のプロセスでのみ発生し、複数モジュールにまたがって表面化していることから、そのプログラム自体、またはそのプロセス固有のシステム利用方法に問題がある可能性が示されています。(Microsoft for Developers)

このようなケースでは、ベンダーへの問い合わせ文面が重要です。

「アプリ終了時にたまに落ちます」だけでは、優先度が低く扱われる可能性があります。代わりに、次の情報を添えると調査が進みやすくなります。

添付・共有すべき情報理由
アプリ名と正確なバージョン既知不具合や修正済みバージョンと照合できる
Windows のバージョンと更新状況OS 依存の問題か切り分けやすい
クラッシュ発生時刻イベントログや監視ログと突合しやすい
クラッシュダンプスタックトレースや破損箇所を確認できる
再現手順ベンダー側で検証しやすくなる
複数端末での発生有無環境依存か製品不具合かを判断しやすい

問い合わせでは、「終了時クラッシュ」だけでなく、「DLL のアンロード処理またはメモリ破損の可能性がある」と明記すると、開発部門にエスカレーションされやすくなります。

開発チームが見直すべき実装ポイント

開発者向けには、今回の記事から学べる点が多くあります。特に C++ やネイティブコードを含むアプリでは、ハンドルの所有権とメモリ破損の検出を重点的に見直すべきです。

HMODULE を単なる整数のように扱わない

今回の事例では、HMODULE の下位ビットが意味を持つことが重要な手掛かりになっています。ポインタやハンドルを「実質的には数値」と見なして加工したり、構造体の境界を越えて書き込んだりすると、わずか 1 ビットの変化でもシステム API の解釈が変わります。

特に危険なのは、次のような実装です。

// 悪い例:所有権が不明な HMODULE を自動解放対象にしてしまう
HMODULE h = GetModuleHandleW(L"example.dll");
// この h を RAII ラッパーに入れてデストラクタで FreeLibrary するのは危険

GetModuleHandle は、指定されたモジュールのハンドルを取得しますが、参照カウントを増やしません。そのため、取得したハンドルを FreeLibrary に渡すべきではないと Microsoft Learn でも説明されています。(Microsoft Learn)

より安全な方針は、次のように「所有するハンドル」と「参照するだけのハンドル」を型や命名で分けることです。

// 所有するハンドル:LoadLibrary で取得し、最後に FreeLibrary する
HMODULE ownedModule = LoadLibraryW(L"example.dll");

// 参照するだけのハンドル:GetModuleHandle で取得し、FreeLibrary しない
HMODULE borrowedModule = GetModuleHandleW(L"example.dll");

メモリ破損は「最初に落ちた場所」が原因とは限らない

今回の Microsoft 記事で実務的に重要なのは、クラッシュ箇所と原因箇所が一致しない点です。DLL 呼び出し時にクラッシュしていても、原因はその DLL ではなく、もっと前に発生した 1 バイトの不正書き込みかもしれません。

調査時は、次の順序で確認すると切り分けやすくなります。

手順確認内容
1クラッシュが発生した DLL や関数を確認する
2その DLL が本当にメモリ上に存在するかを確認する
3DLL のロード・アンロード履歴を確認する
4HMODULE や管理構造体の破損がないかを見る
5同じプロセス内の他クラッシュと共通点を探す
6AddressSanitizer、PageHeap、Application Verifier などで不正書き込みを検出する

ポイントは、クラッシュ単位で個別に直そうとしないことです。Microsoft の記事でも、DLL がメモリから消えていたクラッシュは、「不適切な場所に 01 バイトを書き込む」という根本バグの別表現だったと説明されています。(Microsoft for Developers)

グローバル企業での運用上の注意点

グローバル環境では、同じアプリでも地域、言語、端末イメージ、セキュリティ製品、周辺デバイス、プラグイン構成が異なることがあります。そのため、クラッシュが一部地域だけで発生しても、単なるローカル問題と決めつけない方が安全です。

特に次のような切り口で情報を集めると、原因の絞り込みに役立ちます。

切り口見るべきポイント
地域特定国・地域の端末だけで発生していないか
言語環境IME、ロケール、表示言語、文字コード処理が関係していないか
端末モデル特定メーカーや特定ドライバー構成に偏っていないか
セキュリティ製品EDR、DLP、暗号化、アプリ制御が DLL 読み込みに影響していないか
アプリ構成プラグイン、アドイン、拡張モジュールの差分がないか
更新タイミングWindows 更新、アプリ更新、ドライバー更新後に増えていないか

グローバル向けに管理する場合、イベントログやクラッシュダンプの収集ルールを地域ごとにバラバラにせず、共通のフォーマットで集めることが重要です。たとえば、問い合わせテンプレートに「アプリ終了時か、操作中か」「クラッシュ直前に開いていたファイル」「接続していた周辺機器」「利用していたプラグイン」を含めるだけでも、後続調査の品質が大きく変わります。

よくある誤解と失敗しやすいポイント

今回の内容は低レイヤー寄りのため、運用現場では誤解が起きやすい分野です。特に次の点に注意してください。

誤解正しい見方
DLL がリストにあるならメモリにも存在する管理情報と実際のメモリ状態が食い違うケースがある
終了時クラッシュは業務影響が小さい根本にメモリ破損がある場合、別のタイミングで重大化する可能性がある
落ちた DLL が必ず悪いその前に別モジュールがメモリを壊している可能性がある
FreeLibrary はどの HMODULE に対しても安全ハンドルの取得方法と所有権を確認する必要がある
設定変更で解決できる今回の記事は設定変更の案内ではなく、障害解析の考え方を示すもの

特に FreeLibrary の扱いは注意が必要です。Microsoft Learn では、FreeLibrary はロード済み DLL の参照カウントを減らし、参照カウントがゼロになるとプロセスのアドレス空間からアンロードすると説明されています。つまり、誤ったハンドルや所有していないハンドルに対して呼び出すと、想定外のアンロードにつながる可能性があります。(Microsoft Learn)

企業の管理者が今すぐ実施すべき確認リスト

今回の Microsoft 公式情報を受けて、管理者が現実的に行うべきことは、設定変更ではなく「監視と調査の準備」です。

優先度確認項目具体的なアクション
終了時クラッシュの有無イベントログ、クラッシュレポート、EDR のアプリクラッシュ検知を確認する
影響アプリの特定同じ実行ファイル、同じ DLL、同じバージョンに偏りがないか集計する
ベンダー問い合わせ準備バージョン、再現手順、ダンプ、発生端末情報をまとめる
自社開発アプリの DLL 管理LoadLibrary / FreeLibrary / GetModuleHandle の利用箇所を棚卸しする
ダンプ取得設定再現端末でクラッシュダンプを取得できるようにする
更新履歴の整理OS、アプリ、セキュリティ製品、ドライバーの更新時系列を確認する
利用者への案内「終了時に落ちるだけ」でも報告対象にするよう周知する

グローバル展開している企業では、まず一部地域や一部部門で発生している終了時クラッシュを集計し、同じプロセス名・同じ DLL・同じアプリバージョンに偏っていないかを見るのが現実的です。そこから、ベンダー問い合わせ、自社コードレビュー、端末構成差分の調査へ進めると無駄が少なくなります。

今回の情報をどう受け止めるべきか

「The case of the DLL that was not present in memory despite not being formally unloaded, part 2」は、Microsoft の新機能や仕様変更を知らせる記事ではありません。管理者が何かのスイッチを有効化したり、期限までに移行作業を行ったりする内容でもありません。

しかし、Windows アプリの安定運用という観点では重要です。特に、次の3点を押さえておくと実務に活かせます。

第一に、DLL が「正式にアンロードされていない」ように見えても、メモリ上の実態と一致しているとは限りません。第二に、1 バイトの不正書き込みでも、HMODULE のようなハンドルの意味を変えてしまうことがあります。第三に、アプリ終了時のクラッシュは、目立たないだけで重大なメモリ破損のサインである可能性があります。

管理者は、設定変更を探すよりも、まず自社環境で終了時クラッシュや特定アプリの不安定化が起きていないかを確認してください。開発チームは、DLL ハンドルの所有権、FreeLibrary の呼び出し条件、メモリ破損検出の仕組みを見直すことが次の一手です。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次