tech.guitarrapc.cóm

Technical updates

Docker DesktopリソースセーバーとWSL2のautoMemoryReclaim=gradualは併用できない

WSL2は長年メモリリークがありましたが、.wslconfigのautoMemoryReclaim1を設定することでキャッシュされたメモリを自動解放できます。ただ、autoMemoryReclaim=gradualにしているとDocker DesktopのResource Saver(リソースセーバー)と併用できないようでトラブったのでメモ。

Docker Desktopのリソースセーバーとは

Docker Desktopのリソースセーバーは、一定時間コンテナが実行されていない場合にDocker Desktop Linux VMを自動的に停止することで、ホスト上のDocker DesktopのCPUとメモリの使用量を2GB以上大幅に削減します。デフォルトは5分設定ですが、調整可能です。 リソースセーバーの設定

便利な機能ですが、Docker DesktopをWSL2バックエンドで利用している場合は挙動が違います。具体的には、WSL VMを終了せずdocker-desktopWSLの中で動くDocker Engineをポーズするだけです。WSLは全部のディストリビューションで共有される単一Linux VMを使用しているため、Docker DesktopのVMを終了できないのですね。Linux VMを終了できないため、リソースセーバーはCPU使用率を削減しますがDockerのメモリ使用料を削減しません。そこで利用するように推奨されているのがautoMemoryReclaimです。

WSLの自動メモリ回収

WSL 1.3.100以降、WSL2はautoMemoryReclaimを試験的にサポートしています。 autoMemoryReclaimは、WindowsホストがWSL VMの使用していないメモリを取り戻すことを可能にします。つまり、Dockerコンテナイメージビルド中にWSL VMがLinuxカーネルのページキャッシュ中にGB単位でメモリを保持してもメモリ解放を促します。先ほどのWSL2バックエンドのDocker Desktopでリソースセーバーが機能しないことを踏まえると、まさにほしかった機能です。従来のpageReportingではメモリがほぼ解放されなかったのもあり、個人的にはとても嬉しいです。

autoMemoryReclaimoffgradualdropcacheの3つのモードがあります。機能としてはCgroupsを使用しており、設定値によってCgroups V1、V2のどちらを使うか切り替わります。

  • off: 自動メモリ回収を無効にする
  • gradual: WSLが使用していないメモリを徐々に回収する
  • dropcache: WSLが使用していないメモリをすぐに回収する

設定はMicrosoftのWindows Command Lineブログで紹介されています。軽く振り返ってみましょう。

autoMemoryReclaim=off

これまでの動作です。autoMemoryReclaimを指定しない場合もこの動作になります。 WSL VMが使用していないメモリを回収しません。

Ubuntu 24.04ならCgroups V1/V2の両方が有効になっています。

$ grep cgroup /etc/mtab
tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec,size=4096k,nr_inodes=1024,mode=755 0 0
cgroup2 /sys/fs/cgroup/unified cgroup2 rw,nosuid,nodev,noexec,relatime 0 0
cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
cgroup /sys/fs/cgroup/cpu cgroup rw,nosuid,nodev,noexec,relatime,cpu 0 0
cgroup /sys/fs/cgroup/cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct 0 0
cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
cgroup /sys/fs/cgroup/net_cls cgroup rw,nosuid,nodev,noexec,relatime,net_cls 0 0
cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
cgroup /sys/fs/cgroup/net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio 0 0
cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
cgroup /sys/fs/cgroup/rdma cgroup rw,nosuid,nodev,noexec,relatime,rdma 0 0
cgroup /sys/fs/cgroup/misc cgroup rw,nosuid,nodev,noexec,relatime,misc 0 0
cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,name=systemd 0

autoMemoryReclaim=gradual

.wslconfigで次のように書くと有効になります。2

[wsl2]
# 省略
[experimental]
autoMemoryReclaim=gradual

gradualにすると、5分間のアイドル時間が検出されると段階的にキャッシュを減らしていきます。WSLがアイドルかどうかはCPU使用率が5分間継続して低いかどうかで検出します。

ポイントとして、Cgroups V1が禁止されCgroups V2のみが有効になるようです。なお、gradualが有効になったかは/sys/fs/cgroup/memory.reclaimがあるかで判断できます。

$ grep cgroup /etc/mtab
cgroup2 /sys/fs/cgroup/unified cgroup2 rw,nosuid,nodev,noexec,relatime 0 0

動作をよりカスタマイズしたい場合、Microsoftチームのスクリプトがgistで公開されています。

なお、Microsoftの動作試験で、WSL2でDockerデーモンをサービス実行しているときに壊れるのを確認しているようです。また、Issueを見るとWSL2でsystemdを有効にしていてもトラブルが起きるようです。3

autoMemoryReclaim=dropcache

.wslconfigで次のように書くと有効になります。

[wsl2]
# 省略
[experimental]
autoMemoryReclaim=dropcache

dropcacheにすると、5分間のアイドル時間が検出されると解放可能なキャッシュをすべて解消します。 Cgroups V2は使われず、/proc/sys/vm/drop_cachesが利用されます。Cgroups V1の動作を禁止しないのでアプリケーションを問わなさそうですが、即座というのは微妙なケースもありそうです。

$ grep cgroup /etc/mtab
tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec,size=4096k,nr_inodes=1024,mode=755 0 0
cgroup2 /sys/fs/cgroup/unified cgroup2 rw,nosuid,nodev,noexec,relatime 0 0
cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
cgroup /sys/fs/cgroup/cpu cgroup rw,nosuid,nodev,noexec,relatime,cpu 0 0
cgroup /sys/fs/cgroup/cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct 0 0
cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
cgroup /sys/fs/cgroup/net_cls cgroup rw,nosuid,nodev,noexec,relatime,net_cls 0 0
cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
cgroup /sys/fs/cgroup/net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio 0 0
cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
cgroup /sys/fs/cgroup/rdma cgroup rw,nosuid,nodev,noexec,relatime,rdma 0 0
cgroup /sys/fs/cgroup/misc cgroup rw,nosuid,nodev,noexec,relatime,misc 0 0
cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,name=systemd 0

リソースセーバーとautoMemoryReclaim=gradualを併用するとハングする

Windows 11 24H2でDocker Desktopのリソースセーバーを有効にしていると、WSL2でディスクから読み取る操作の途中でハングする症状が発生しました。

$ wsl -v
WSL version: 2.4.13.0
Kernel version: 5.15.167.4-1
WSLg version: 1.0.65
MSRDC version: 1.2.5716
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26100.1-240331-1435.ge-release
Windows version: 10.0.26100.3775

WSL2起動直後にどんなコマンドでも再現するわけではなく、WSL2である程度の時間実行していると急に発生します。私の場合、WSLのUbuntu環境構築でapt実行中にハングしました。

# 新規WSL2 Ubuntu24.04でいつもハングする
# aptの実行中に突然止まるので原因が分からずとまどう
- name: "Install apt tools"
  become: true
  ansible.builtin.apt:
    pkg: "{{ apts }}"
    update_cache: true
  register: apt_result

タイミング的に、Docker Desktopでリソースセーバーモードが有効になった時ハングするようです。

Docker Desktopのリソースセーバーモード

リソースセーバーモードから再開すると、WSL2がハングしている状態から復帰します。

リソースセーバーモードからDockerを再開する

解消方法

本問題はIssueが存在しており、対策がいくつか紹介されています。私は1のautoMemoryReclaim=dropcacheにしてDocker Desktopのリソースセーバーは有効にしています。

  • 恒久対策1: autoMemoryReclaim=dropcacheか無効にする
  • 恒久対策2: autoMemoryReclaim=gradualかつ、Docker Desktopのリソースセーバーモードを無効
  • 恒久対策3: Docker Desktopのリソースセーバーモードを無効
  • 一時対策: Docker Desktopのリソースセーバーモードを解除(Docker Desktopを再開)する

悪いお知らせですが、まだプレリリースなもののWSL 2.5.1でCgroups V1のサポートが削除されるようです。 WSL 2.5.1で.wslconfigを調整していないのに症状が出たという報告もあるので長期化するかも知れないです。その場合、Docker Desktopのリソースセーバーを無効にしましょう。

私もWSL 2.5.1でWSL2がハングするトラブルと出会ったので、ちょっとWSL 2.5.1は様子見しています。

まとめ

Docker DesktopのリソースセーバーでWSL2の動作に影響できると考えていなかったので、出会ったときは手こずりました。 WSLの方向性としては、Cgroups V2とDocker Desktopの対応が進むか、Docker Desktopのリソースセーバーを無効にするしかなさそうで頭痛いです。

参考

Issue

autoMemoryReclaimの手動調整スクリプト


  1. 2025年現在は試験的な機能
  2. .wslconfigを書き換えた場合、wsl --shutdownでWSLを再起動しましょう
  3. 私はWSLでsystemdを使っていないので遭遇していません