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割という塊は、体感で想像していたより大きかった(アプリ層はもっと Arm64 寄りだと思い込んでいた)。
計測日は2026-07-25で、JSON の作成も2026年7月25日に行った。対象は実際に手元で Get-AppxPackage から取れたパッケージだけに絞っている。ここで言う MSIX / Appx は実行中のプロセスではなく、登録されているパッケージの棚卸しなので、いま CPU を使っているものの比率とは少し違う。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 部品の一覧ではないことがここでも分かる。つまり、この棚卸しは 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% がフレームワークだった(この層をアプリ本体と同じ気分で数えると、かなり見方を誤る)。この層が重複の温床になり、名前だけを見て「同じものが何個もある」と感じても、実際には依存先のアーキテクチャ違いが並んでいるだけ、という読み方が必要になる(ここを雑に見ると非 Arm64 の数を大きく感じすぎる)。
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 時間を使っているものは、たぶん同じ比率にはならないのではないだろうか。