link 未来から過去へ表示(*)
link 過去から未来へ表示

link もっと前
   2021年 1月 2日 ---> 2020年 12月 24日
link もっと後

2021年 1月 2日

Windows と Linux のメモリ割り当て戦略

新年早々、Windows と Linux のメモリ割り当て戦略の基本的な違いをすっかり忘れていて、ひどい目に合いました。

症状としては Steam でゲームをしてると頻繁にゲームが落ちたり、ブラウザがクラッシュします。

何を調べた?

疑った順に、

AMD のグラフィクスドライバ?
  • バージョンアップしてもダメ。
  • クロックダウンしてもダメ。
  • 無効化し(Intel 内蔵グラフィクスに切り替え)てもダメ。
熱暴走?
  • Intel 内蔵+クロックダウンで 50℃行かなくてもダメ。
メモリ不足?
  • 物理メモリは数 GB 余っているのにダメ。

結論は?

仮想メモリの枯渇でした。Windows は仮想メモリを物理メモリ+ページングファイルの合計量までしか割り当てません。私の環境は物理メモリ 16GB+ページングファイル 1GB に切り詰めていたため、仮想メモリは 17GB までしか確保できません。

ゲーム+ブラウザを起動すると仮想メモリの消費量が 17GB を超えるときがあります。仮想メモリの割り当て量が上限ギリギリに達して、ゲームもしくはブラウザの運が悪い方が、仮想メモリを要求すると、割り当てに失敗します。

すると NULL ポインタが返り、NULL ポインタにアクセスしてゲーム or ブラウザがクラッシュしてしまうようです。誰一人として、仮想メモリの割り当て失敗を想定せんの?誰か 1人くらい VirtualAlloc() が失敗したって教えてくれても良いのに……。

対策は?

ページングファイルを適当に増やせば(とりあえず 16GB くらいにした)安定しました。

なぜそう判断した?

気づいたきっかけはゲーム(Cities: Skylines)のクラッシュダンプです。


クラッシュダンプのエラーログ

エラーログを見ると paging file の空きが 1MB しかありません。Windows ではこれは仮想メモリの空きを表すそうです。これを知らなかったがために、全然関係ないドライバとか熱暴走を疑い、遠回りしてしまいました。

確認方法は?

タスクマネージャーで「コミット済み」の値をチェックすると、仮想メモリの使用量がわかります。これがゲーム+ブラウザで 17GB を超えていました。


タスクマネージャー「コミット済み」の例

ダメ押しで、下記のような VirtualAlloc() API を呼んで仮想アドレスを大量にガメる(物理メモリはほぼ消費しない)プログラムを書いて、わざと仮想メモリだけを枯渇させました。

1GB ずつ仮想メモリをガメるプログラム

#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 は仮想メモリ割当てが保守的です。仮想メモリの割り当て上限=物理メモリ+ページファイルの合計となります。

  • 利点: 全プロセスが仮想メモリ全域にアクセスしても、物理メモリ+スワップで対応できます。仮想メモリと物理メモリの対応は必ずできて、プロセスを Kill する必要は原理的に発生しません。
  • 欠点: 仮想メモリを確保だけしてアクセスしないプロセスが大量にいると、仮想メモリが先に枯渇します。物理メモリは遊んだままで無駄になります。

Linux は物理メモリ+スワップファイルの合計<仮想メモリの割り当て上限となります(over commitment)。

  • 利点: 仮想メモリを無駄に確保するやつがいても、物理メモリ+スワップを使い切れます。
  • 欠点: 全プロセスが仮想メモリにアクセスしてしまうと、仮想メモリに紐づける物理メモリ or スワップ領域が不足し、メモリ使用量を減らすためプロセスを Kill せざるを得なくなります。

Windows と Linux のメモリ割り当て戦略は、利点と欠点が逆になるだけで、どっちもどっちです。

まとめ

今回の教訓をおさらいすると、Windows を使っているのに、Linux と同じノリでページファイルを 1GB とか小さいサイズに削ると、速攻で仮想メモリが枯渇してひどい目に合うんでやめようね!ってことです。

編集者: すずき(更新: 2021年 1月 3日 04:24)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2020年 12月 31日

デザイン変更

記事以外の表示(リンクとか編集ボタンとか)が縦に並んでいて、横長のディスプレイで見たときに邪魔なので、ちょっとだけデザインを変えて縦方向の長さを詰めました。

デザインはあまり詳しくないですが、もっと文字が読みやすくなるようにするにはどうしたら良いんでしょうね……?

編集者: すずき(更新: 2020年 12月 31日 18:17)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
   2021年 1月 2日 ---> 2020年 12月 24日
link もっと後

管理用メニュー

link 記事を新規作成

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDF ファイル RSS 1.0
QR コード QR コード

最終更新: 1/17 14:28

カレンダー

<2021>
<<<01>>>
-----12
3456789
10111213141516
17181920212223
24252627282930
31------

最近のコメント 5件

  • link 20年12月20日
    すずき 「パック旅行や旅行代理店に割り当てられた専...」
    (更新:12/21 19:00)
  • link 20年12月20日
    hdk 「羽田鹿児島便、ANA直接予約はほとんどし...」
    (更新:12/21 08:17)
  • link 20年09月10日
    すずき 「追加情報。最新の Debian Test...」
    (更新:10/07 16:48)
  • link 20年09月20日
    hdk 「最近は音楽聞く時やビデオ視聴時はミニコン...」
    (更新:09/24 21:43)
  • link 20年09月20日
    すずき 「ありゃー、同じ壊れ方ですね。\n新たなヘ...」
    (更新:09/24 00:23)

最近の記事 3件

link もっとみる
  • link 21年01月16日
    すずき 「[QEMU のデバッグ用ビルド方法] たまに RISC-V 向けの...」
    (更新:01/17 14:28)
  • link 20年08月27日
    すずき 「[サーバ向けプロセッサでは最強の Intel] Twitter で...」
    (更新:01/10 19:49)
  • link 21年01月03日
    すずき 「[Windows の仮想メモリサイズの謎] Windows で「コ...」
    (更新:01/03 13:04)

こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報