Windows 11 25H2 の Working Set 挙動を Swift(Windows)で実測してみた
― Swift + Win32 API で Working Set / PageFault を“実測”してみた ―
本記事の検証は筆者の環境・条件での観測結果であり、
製品の不具合や仕様を断定するものではありません。
同様の結果が再現されるかは環境差があります。
概要
前回の記事では、
Delphi + 組み込みアセンブラを用いて
Windows 11 25H2 における Working Set(WS)と PageFault の挙動を実測した。
今回は同じ検証を、
Swift(Windows) を用いて行った。
Swift 6.x(Windows / MSVC)
Win32 API(K32GetProcessMemoryInfo)を直接呼び出し
UnsafeMutableRawPointer による生メモリアクセス
sleep なし
という条件で、
Touched(触ったメモリ量)
Working Set
PageFaultCount
を Delphi / C / Rust と同じ粒度で取得した。
なぜ Swift(Windows)なのか
Swift は一般に、
Apple 専用言語
高級言語
ARC やランタイムが重い
といった印象を持たれがちだ。
しかし Windows では、
LLVM + MSVC
Win32 API を直接呼び出し可能
GC なし(ARC)
ネイティブコード生成
という 完全なネイティブ言語として動作する。
👉
「言語やランタイム差ではなく、
OS のメモリ管理の判断なのか?」
を確認するには、むしろ都合が良い。
検証方針
前回の Delphi + ASM 版と揃え、以下を方針とした。
OS のメモリ管理を直接観測する
言語ランタイムの影響を極力排除する
sleep による“時間の猶予”は与えない
そのため、
UnsafeMutableRawPointer を使用
ページ単位(4KB)で書き込みアクセス
Win32 API から WS / PF を直接取得
という構成を採用した。
検証内容
テスト条件
OS:Windows 11 25H2(x64)
メモリ確保:512MB
アクセス方式:Page stride(4KB ごと)
表示周期:10MB ごと
使用コード(Swift)
メモリ確保
let sizeMB = 512
let size = sizeMB * 1024 * 1024
let page = 4096
let ptr = UnsafeMutableRawPointer.allocate(
byteCount: size,
alignment: page
)
Page Touch + WS / PF 取得
import WinSDK
let hProcess = GetCurrentProcess()
var pmc = PROCESS_MEMORY_COUNTERS_EX()
pmc.cb = DWORD(MemoryLayout<PROCESS_MEMORY_COUNTERS_EX>.size)
for offset in stride(from: 0, to: size, by: page) {
ptr.storeBytes(of: UInt8(1), toByteOffset: offset, as: UInt8.self)
if offset % (10 * 1024 * 1024) == 0 {
withUnsafeMutablePointer(to: &pmc) {
$0.withMemoryRebound(
to: PROCESS_MEMORY_COUNTERS.self,
capacity: 1
) {
_ = K32GetProcessMemoryInfo(
hProcess,
$0,
DWORD(MemoryLayout<PROCESS_MEMORY_COUNTERS_EX>.size)
)
}
}
print(
"Touched \(offset/1024/1024) MB | " +
"WS \(Int(pmc.WorkingSetSize)/1024/1024) MB | " +
"PF \(pmc.PageFaultCount)"
)
}
}
実行結果(Windows 11 25H2)
ログ抜粋
Touched 100 MB | WS 108 MB | PF 27930
Touched 200 MB | WS 208 MB | PF 53580
Touched 300 MB | WS 308 MB | PF 79230
Touched 400 MB | WS 408 MB | PF 104880
Touched 500 MB | WS 508 MB | PF 130530
観測から分かること
ページアクセスごとに PageFault が発生している
Touched と Working Set はほぼ比例
Swift 特有の挙動は見られない
このフェーズの挙動は、
Delphi / C / Rust / Zig で行った初期挙動と一致している。
Delphi + ASM 版との比較
観点Delphi + ASMSwiftメモリ確保VirtualAllocUnsafeMutableRawPointerアクセス組み込みASMSwiftWS / PF 取得GetProcessMemoryInfoK32GetProcessMemoryInfo初期挙動一致一致
👉
違いは言語ではなく、観測フェーズにある。
Working Set が「張り付く/落ちる」条件
今回の Swift 版でも、以下は前回と同様だった。
Touch を継続中
→ Working Set は増加Touch 完了後、放置
→ 数秒〜十数秒で WS は縮小sleep を挿入
→ WS 昇格が発生
👉
アクセス量ではなく、
アクセスの継続性・滞在時間が重要に見える。
結論
Swift(Windows)でも
Working Set は「量」ではなく「時間」を見て管理されているPageFault が増えても
WS として保持されるとは限らない言語差・ランタイム差は
本検証条件では影響しなかった
👉
Windows 11 25H2 のメモリ管理の性格は、言語を選ばない
まとめ
Swift でも Win32 API を直接呼び出せる
Swift でも OS が返す WS / PF の値は他言語と一致する
変わったのはアプリではなく、Windows 11 25H2 のメモリ管理
OS の判断は言語を問わない。
Working Set をどう扱うかは、
アプリ側の設計で吸収する必要がある。
