MSIX 240本の Architecture を数えたら Arm64 は145本だった
Get-AppxPackage で見えた MSIX / Appx 240本のうち、Arm64 は145本、Neutral は54本、X64 は25本、X86 は16本だった。
Surface Pro 11th Edition の Windows 11 ARM64 環境なら、Store アプリ層はもうかなり Arm64 に寄っているはずだと思い込んでいた。ところが Arm64 は60.4%で、非 Arm64 は95本、39.6%も残っている。見ているのは起動中プロセスではなく登録済みパッケージの棚卸しとはいえ、ほぼ4割という数字は正直、想像より大きかった。
計測日は2026-07-25で、JSON の作成も2026年7月25日に行った。対象は手元の Get-AppxPackage から取れたパッケージだけに絞っている。OS に同梱された部品、Store から入ったアプリ、ランタイム系のフレームワークが同じ土俵に並ぶ形なので、この混ざり方があとで読みにくさになる。
X64 と X86 の顔ぶれも、数えてみる前の印象とかなりずれていた。古い互換レイヤーだけが掃除されずに残っている、という単純な話ではない気がする。Microsoft.PowerAutomateDesktop、Microsoft.AzureVpn、Microsoft.DirectXRuntime、Microsoft.OutlookDesktopIntegrationServices、Microsoft.WritingAssistant、1915OliverSchwendener.Ueli が X64 側に残っていた。X86 側にも Microsoft.DirectXRuntime や Microsoft.Ink.Handwriting.ja-JP.1.0 がある。
JSON に落とすまで
最初は PowerShell の画面出力をそのまま眺めれば足りると思っていた。実際には Architecture が文字列ではなく列挙型として返ってくるので、見た目だけで読もうとすると危ない。X64 などの文字列がそのまま出るつもりでいたのに、実際は違った。JSON に落としてから数えるほうが安全だろうと、途中で方針を切り替えている。
Get-AppxPackage | Select-Object Name, Architecture, SignatureKind, IsFramework |
ConvertTo-Json -Depth 4 |
Out-File .ppx.json -Encoding utf8
この段階で一度ハマってしまった。Out-File -Encoding utf8 が BOM を付けて出力したため、Python 側の json.loads が先頭で止まったのだ。PowerShell 側では自然に見えていたので、気づくまで少しかかった。ファイルを開く側を encoding="utf-8-sig" に変えて読み直している。BOM 付き UTF-8 を想定していなかったのが、今回の地味な失敗だ。
もうひとつの勘違いは Architecture の中身だった。ConvertTo-Json で吐くと、X86 や Arm64 ではなく数値が並ぶ。手元では、0 が X86、5 が Arm、9 が X64、11 が Neutral、12 が Arm64、14 が X86OnArm64 に対応する。この対応表を見ないまま集計したので、最初の結果は 0、9、11、12 の羅列だ。なぜ 12 が多いのか自分でも説明できなくて、しばらく詰まることになった。
import json
from collections import Counter
data = json.loads(path.read_text(encoding="utf-8-sig"))
arch = Counter(item["Architecture"] for item in data)
実際に直した後は、数値の列挙型を名前に戻してから集計した。この変換を飛ばすと、表だけは作れても意味を読み違える。エラーが出ないので怖い種類の失敗だった。
Architecture の棚卸し
アーキテクチャ別の内訳はこうなった。割合は240本に対する比率で計算している。
| Architecture | 本数 | 割合 |
|---|---|---|
| Arm64 | 145本 | 60.4% |
| Neutral | 54本 | 22.5% |
| X64 | 25本 | 10.4% |
| X86 | 16本 | 6.7% |
Arm64 が最多なのは自然だが、Neutral の54本も大きい。Microsoft.AccountsControl、Microsoft.Windows.CloudExperienceHost、Microsoft.Windows.ContentDeliveryManager、Windows.PrintDialog のような OS 寄りのものが Neutral に入っている。CPU 命令セットを持つ実行バイナリというより、リソースやホスト寄りのパッケージとして見るほうが近い気がする。
署名種別も同じデータから数えた。Architecture だけを見ると OS 部品と Store 系が同じ顔に見えてしまうのが気になっていたので、この角度から見直すと少し読み方が変わった。
| SignatureKind | 本数 | 割合 |
|---|---|---|
| Store | 124本 | 51.7% |
| Developer | 65本 | 27.1% |
| System | 51本 | 21.3% |
System 署名は51本で、Store 署名の124本が半分を超えている。Developer 署名も65本ある。単なる OS 部品の一覧ではなく、ユーザー環境に入っている Store 系や開発者署名のパッケージもかなり混ざる形だ。Windows そのものの移植状況を見る表として読むと過剰で、手元環境のアプリ層を含むスナップショットとして読むのがよさそうだ。
x64 と x86 に残っていたもの
X64 の25本を見ると、まずランタイム系が多い。Microsoft.VCLibs.140.00、Microsoft.VCLibs.140.00.UWPDesktop、Microsoft.NET.Native.Runtime.2.2、Microsoft.NET.Native.Framework.2.2、Microsoft.UI.Xaml.2.8、Microsoft.WindowsAppRuntime.1.6、Microsoft.WindowsAppRuntime.1.7、Microsoft.WindowsAppRuntime.1.8、Microsoft.WindowsAppRuntime.2 が並んでいる。アプリ本体だけを想像していると棚卸しの粒度に少し驚く。
アプリ名として目に付くものもある。Microsoft.Xbox.TCUI、Microsoft.OutlookDesktopIntegrationServices、Microsoft.AzureVpn、Microsoft.Limitless、Microsoft.PowerAutomateDesktop、Microsoft.WritingAssistant は X64 だった。MicrosoftWindows.Speech.en-US.1 と MicrosoftWindows.Speech.ja-JP.1 も X64 に入っている。
X86 の16本はさらにランタイム寄りで、古いアプリ本体がそのまま残っている、という読みだけでは足りないことがここでも分かった。Microsoft.VCLibs.140.00、Microsoft.VCLibs.120.00.UWPDesktop、Microsoft.VCLibs.110.00.UWPDesktop、Microsoft.NET.Native.Framework.2.2、Microsoft.NET.Native.Runtime.2.2、Microsoft.UI.Xaml.2.7、Microsoft.UI.Xaml.2.8、Microsoft.WindowsAppRuntime.1.5、Microsoft.WindowsAppRuntime.1.6、Microsoft.WindowsAppRuntime.1.7、Microsoft.WindowsAppRuntime.1.8、Microsoft.WindowsAppRuntime.2 がある。
X86 が残っているからといって即座に「古いアプリが動いている」と決めつけるのは間違いだと後から気づいた。VCLibs や Windows App Runtime のようなフレームワークは、依存するアプリに合わせて複数アーキテクチャが同居する。今回の frameworks は86本で、全体の35.8% がフレームワークだった。この層をアプリ本体と同じ気分で数えると見方をかなり誤る。
Microsoft.VCLibs.140.00 は X86、X64、Arm64 が同時に存在していた。Microsoft.Services.Store.Engagement も X86、X64、Arm64 が並ぶ。ひとつの名前が複数アーキテクチャで入るので、パッケージ名の種類だけを数えると状況を見落とす。
失敗したところ
失敗は地味で、PowerShell の出力をテキストとして見て、そこから雑にパースすれば終わると思っていた。画面で読めるものをデータとしても読める、と雑に扱っていたのだ。けれど ConvertTo-Json にした時点で BOM と列挙型の数字という2つの罠を踏んだ。
BOM のほうは分かりやすく、Python の json.loads が先頭で落ちる。ファイルをバイナリで見れば原因に気づけるので、失敗としては親切なほうだった。utf-8-sig に変えると読める。
Architecture のほうは気づくまで少し時間がかかった。集計結果が 12、11、9、0 のように出て、件数だけはそれらしく見える。なぜ名前ではなく数字なのか、とその場で立ち止まればよかったのに、最初はそのまま表にしそうになった。数字が正しくても、意味づけが間違っていると表全体が壊れてしまうので怖い。
今回は JSON の arch_enum_map に対応を残した。0=X86、5=Arm、9=X64、11=Neutral、12=Arm64、14=X86OnArm64 という対応だ。これを記事側にも書いておくと、後で同じデータを見返したとき、なぜ 12 が一番多いのかを思い出せる。未来の自分向けの注釈でもある。
数で押さえる意味
個人的には、Arm64 Windows の移行状況は体感だけで語りがちだった。普段使うアプリが普通に動くと、もう十分ネイティブ化が進んだように感じる。逆に、ひとつでも x64 の重いアプリに当たると、まだ移行途上に見えてしまう。体感だけだと、この振れが大きい。
今回の240本は、その中間を見せてくれた。Arm64 は145本で過半数を占める。けれど Neutral が54本、X64 が25本、X86 が16本あり、非 Arm64 も95本ある。ストアアプリ層でも4割強に近い塊がネイティブ以外として残る、という見方になった。
手元では、この数字を見てランタイム系を別枠で見るようになった。Microsoft.WindowsAppRuntime や Microsoft.VCLibs が複数アーキテクチャで入るのは、悪い兆候というより互換性のための在庫に近い。一方で、Microsoft.PowerAutomateDesktop や Microsoft.AzureVpn のような実アプリ名が X64 に残るなら、そこは起動時の挙動やエミュレーションの影響を別に測りたい。
ネイティブ移行がどこまで進んだかを、今回は体感ではなく240本の棚卸しとして押さえられた。次は、登録済みパッケージではなく実際に起動したプロセスと突き合わせたい。パッケージとして残っているものと、日常で CPU 時間を使っているものは、たぶん同じ比率にはならないのではないかと思っている。