Windows で「コミット済み」(=仮想メモリの合計)の値を求める方法がさっぱりわかりません。タスクマネージャーの「パフォーマンス」タブには下記のように値が表示されています。
しかしタスクマネージャーの「詳細」タブに表示される、各プロセスのコミットサイズ(=仮想メモリサイズのことらしい)を足しても全く足りません。どういうこと??
コミットサイズが全然信用できない例を挙げれば、AMD の Radeon ドライバ関連で AMDRSServ.exe というプロセスがいます。このプロセスをタスクマネージャーで見ると「5MBしか使ってないよ」とおっしゃっています。
ところがプロセスを強制終了させると、突然 700MB ほど(6.2GB → 5.5GB)仮想メモリが解放されます。700MB も使っているプロセスはありませんでしたが、700MB どこから来た?意味不明ですね。
たぶんカーネル側というかドライバ内で仮想メモリをでかく取ると「コミット済み」と「各プロセスのコミットサイズの合計」の乖離が激しくなるんじゃないか?と予想していますが、調べ方がわかりません。
Windows を使っていて仮想メモリが枯渇するような事態に陥り、調べる必要が出てきたとしても、タスクマネージャーの表示してる「コミットサイズ」は全然信用できないってことです。ひどい作りだなあ、もう。
新年早々、Windows と Linux のメモリ割り当て戦略の基本的な違いをすっかり忘れていて、ひどい目に合いました。
症状としては Steam でゲームをしてると頻繁にゲームが落ちたり、ブラウザがクラッシュします。
疑った順に、
仮想メモリの枯渇でした。Windows は仮想メモリを物理メモリ+ページングファイルの合計量までしか割り当てません。私の環境は物理メモリ 16GB+ページングファイル 1GB に切り詰めていたため、仮想メモリは 17GB までしか確保できません。
ゲーム+ブラウザを起動すると仮想メモリの消費量が 17GB を超えるときがあります。仮想メモリの割り当て量が上限ギリギリに達して、ゲームもしくはブラウザの運が悪い方が、仮想メモリを要求すると、割り当てに失敗します。
すると NULL ポインタが返り、NULL ポインタにアクセスしてゲーム or ブラウザがクラッシュしてしまうようです。誰一人として、仮想メモリの割り当て失敗を想定せんの?誰か 1人くらい VirtualAlloc() が失敗したって教えてくれても良いのに……。
ページングファイルを適当に増やせば(とりあえず 16GB くらいにした)安定しました。
気づいたきっかけはゲーム(Cities: Skylines)のクラッシュダンプです。
エラーログを見ると paging file の空きが 1MB しかありません。Windows ではこれは仮想メモリの空きを表すそうです。これを知らなかったがために、全然関係ないドライバとか熱暴走を疑い、遠回りしてしまいました。
タスクマネージャーで「コミット済み」の値をチェックすると、仮想メモリの使用量がわかります。これがゲーム+ブラウザで 17GB を超えていました。
ダメ押しで、下記のような VirtualAlloc() API を呼んで仮想アドレスを大量にガメる(物理メモリはほぼ消費しない)プログラムを書いて、わざと仮想メモリだけを枯渇させました。
#include <cstdio>
#include <cstdlib>
#include <windows.h>
#define CNT 16
int main()
{
const size_t s = 1024 * 1024 * 1024;
char buf[1024], *pb;
void *p[CNT];
for (int c = 0; c < CNT; c++) {
p[c] = VirtualAlloc(NULL, s, MEM_COMMIT, PAGE_READWRITE);
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buf, sizeof(buf) - 1, NULL);
printf("%s\n", buf);
pb = (char*)p[c];
for (size_t i = 0; i < s / 8192; i++)
pb[i] = (char)i;
}
for (int c = 0; c < CNT; c++)
VirtualFree(p[c], s, MEM_DECOMMIT);
return 0;
}
この状態でゲームを動かすと容易に同じクラッシュが起こせます。というわけで仮想メモリの枯渇で確定と判断しました。
Windows と Linux の仮想メモリ割り当て戦略は全く違うのに、同じノリで Windows のページングファイルを削ってしまったことですね……。一応、違いは知っていたんですが、行動に活かせず思い切りハマりました。
Windows は仮想メモリ割当てが保守的です。仮想メモリの割り当て上限=物理メモリ+ページファイルの合計となります。
Linux は物理メモリ+スワップファイルの合計<仮想メモリの割り当て上限となります(over commitment)。
Windows と Linux のメモリ割り当て戦略は、利点と欠点が逆になるだけで、どっちもどっちです。
今回の教訓をおさらいすると、Windows を使っているのに、Linux と同じノリでページファイルを 1GB とか小さいサイズに削ると、速攻で仮想メモリが枯渇してひどい目に合うんでやめようね!ってことです。
記事以外の表示(リンクとか編集ボタンとか)が縦に並んでいて、横長のディスプレイで見たときに邪魔なので、ちょっとだけデザインを変えて縦方向の長さを詰めました。
デザインはあまり詳しくないですが、もっと文字が読みやすくなるようにするにはどうしたら良いんでしょうね……?
合計:
本日:
< | 2021 | > | ||||
<< | < | 01 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2016.
Powered by PHP 5.2.17.
using GD bundled (2.0.34 compatible)(png support.)