Swap

什麼可以使用我的 6GB 交換空間?

  • March 21, 2018

我有一個謎:什麼在使用我的 6GB 交換空間?我的核心版本是4.15.9-300.fc27.x86_64.

這發生在一些崩潰之後。 dmesg顯示我在 gnome-shell 程序(屬於 gdm)和後來的一些 firefox 程序(Chrome_~dThread,在 libxul.so 中)中有段錯誤。 coredumpctl -r在我目前的啟動中沒有顯示其他崩潰。

1.freedf -t tmpfs

# free -h
             total        used        free      shared  buff/cache   available
Mem:           7.7G        1.2G        290M        5.4G        6.1G        761M
Swap:          7.8G        6.0G        1.8G

# swapoff -a
swapoff: /dev/dm-1: swapoff failed: Cannot allocate memory

# df -h -t tmpfs
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G   17M  3.9G   1% /dev/shm
tmpfs           3.9G  1.9M  3.9G   1% /run
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
tmpfs           3.9G   40K  3.9G   1% /tmp
tmpfs           786M   20K  786M   1% /run/user/1000

我還手動檢查了每個程序的掛載命名空間是否有任何額外的 tmpfs。沒有其他掛載的 tmpfs(或者它們是相同的 - 所以只有 17M,並且有不到 10 個不同的掛載命名空間)。

2.ipcs

# ipcs --human

------ Message Queues --------
key        msqid      owner      perms      size         messages    

------ Shared Memory Segments --------
key        shmid      owner      perms      size       nattch     status      
0x00000000 20643840   alan-sysop 600          512K     2          dest         
0x00000000 22970369   alan-sysop 600           36K     2          dest         
0x00000000 20774914   alan-sysop 600          512K     2          dest         
0x00000000 20905987   alan-sysop 600          3.7M     2          dest         
0x00000000 23461892   alan-sysop 600            2M     2          dest         
0x00000000 20873221   alan-sysop 600          3.7M     2          dest         
0x00000000 22511622   alan-sysop 600            2M     2          dest         
0x00000000 28278791   alan-sysop 600           60K     2          dest         
0x00000000 23003144   alan-sysop 600           36K     2          dest         
0x00000000 27394057   alan-sysop 600           60K     2          dest         
0x00000000 29622282   alan-sysop 600          156K     2          dest         
0x00000000 27426828   alan-sysop 600           60K     2          dest         
0x00000000 28246029   alan-sysop 600           60K     2          dest         
0x00000000 29655054   alan-sysop 600          156K     2          dest         
0x00000000 29687823   alan-sysop 600          512K     2          dest         

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     
0x002fa327 98304      root       600        2

3.程序記憶體

每個程序的交換使用腳本說程序記憶體只佔 54MB 的交換:

PID=1 swapped 2292 KB (systemd)
PID=605 swapped 4564 KB (systemd-udevd)
PID=791 swapped 324 KB (auditd)
PID=793 swapped 148 KB (audispd)
PID=797 swapped 232 KB (sedispatch)
PID=816 swapped 120 KB (mcelog)
PID=824 swapped 1544 KB (ModemManager)
PID=826 swapped 152 KB (rngd)
PID=827 swapped 300 KB (avahi-daemon)
PID=829 swapped 1688 KB (abrtd)
PID=830 swapped 836 KB (systemd-logind)
PID=831 swapped 432 KB (dbus-daemon)
PID=843 swapped 368 KB (chronyd)
PID=848 swapped 312 KB (avahi-daemon)
PID=854 swapped 476 KB (gssproxy)
PID=871 swapped 1140 KB (abrt-dump-journ)
PID=872 swapped 1280 KB (abrt-dump-journ)
PID=873 swapped 1236 KB (abrt-dump-journ)
PID=874 swapped 14196 KB (firewalld)
PID=911 swapped 592 KB (mbim-proxy)
PID=926 swapped 1356 KB (NetworkManager)
PID=943 swapped 17936 KB (libvirtd)
PID=953 swapped 200 KB (atd)
PID=955 swapped 560 KB (crond)
PID=1267 swapped 284 KB (dnsmasq)
PID=1268 swapped 316 KB (dnsmasq)
PID=10397 swapped 160 KB (gpg-agent)
PID=14862 swapped 552 KB (systemd-journal)
PID=18131 swapped 28 KB (login)
PID=18145 swapped 384 KB (bash)
Overall swap used: 54008 KB

  1. 到目前為止,我假設沒有umount -l在完整的 tmpfs 上使用過的程序。我沒有嘗試為任何持有這種隱藏 tmpfs 打開的人抓取 /proc/*/fd 。
  2. 我想我也假設沒有人建造了一個巨人memfd並把它打開……哈哈,我為什麼會懷疑這樣的事情……嗚咽。

附加到程序的 memfd 名稱對我來說似乎是無辜的:

# ls -l /proc/*/fd/* 2>/dev/null|grep /memfd:
lrwx------. 1 alan-sysop alan-sysop 64 Mar 18 22:52 /proc/20889/fd/37 -> /memfd:xshmfence (deleted)
lrwx------. 1 alan-sysop alan-sysop 64 Mar 18 22:52 /proc/20889/fd/53 -> /memfd:xshmfence (deleted)
lrwx------. 1 alan-sysop alan-sysop 64 Mar 18 22:52 /proc/20889/fd/54 -> /memfd:xshmfence (deleted)
lrwx------. 1 alan-sysop alan-sysop 64 Mar 18 22:52 /proc/20889/fd/55 -> /memfd:xshmfence (deleted)
lrwx------. 1 alan-sysop alan-sysop 64 Mar 18 22:52 /proc/20889/fd/57 -> /memfd:xshmfence (deleted)
lrwx------. 1 alan-sysop alan-sysop 64 Mar 18 22:52 /proc/20889/fd/60 -> /memfd:xshmfence (deleted)
lrwx------. 1 alan-sysop alan-sysop 64 Mar 18 22:52 /proc/21004/fd/6 -> /memfd:pulseaudio (deleted)

這些 memfd 看起來是無辜的,因為: Process 20889 是我目前的Xorg,它在 6GB 交換之後。同樣,程序 21004 確實是我的 pulseaudio 程序,並且該程序的創建時間晚於建立 6GB 的交換。

理論上,我擔心的那些也可能處於不確定狀態,附加到 unix 套接字消息並且從未閱讀過。


編輯1

在停止systemd-logind(本地 Xorg 通過死亡來響應)並重新啟動 Xorg 之後,我看到整個 6GB 的交換空間都被清除了。

注意我忘了我需要重新開始登錄。雖然 lennart 告訴我 logind 不應該被匯流排啟動,但 logind 立即重新啟動。這是來自journalctl -b,即係統日誌,中間沒有刪除任何消息:

Mar 18 23:14:12 alan-laptop systemd[1]: Stopped Login Service.
Mar 18 23:14:12 alan-laptop dbus-daemon[831]: [system] Activating via systemd: service name='org.freedesktop.login1' unit='dbus-org.freedesktop.login1
Mar 18 23:14:12 alan-laptop systemd[1]: Starting Login Service...

這與 logind 相關,然後經歷了幾次崩潰的循環。這是這個版本的 logind 的預期結果(修復它的 PR 已在上游合併,在我的問題報告之後)。

所以這並不能完全隔離一個單獨的原因,我真的應該在殺死它之前檢查 fds logind 所持有的。

問題

我在上述檢查中是否遺漏了任何可能的交換使用者? (非破壞性的,在 EDIT1 之前)。

有沒有更好的方法來獲取我上面列出的任何可能的使用者的使用報告?也就是說,是否有一種替代方法可以糾正我沒有註意到的一些不准確之處?或者更容易執行,並在再次發生這種情況時獲得快速結果的東西?

有沒有人有一個很好的腳本來檢查 fds 打開一個“隱藏​​的”tmpfs(一個與 tmpfs 分離的 tmpfs umount -l)?

有沒有人有一個很好的方法來檢查 memfds 的記憶體使用情況?

有什麼方法可以檢查在未讀的 unix 套接字消息中是否存在大量 memfds?(這些天才中的任何一個在實現 memfds 時是否考慮過這一點,memfds 是明確用於傳遞 unix 套接字的?)

EDIT2:我是否正確猜測圖形設備(DRM)的文件描述符可以包含對可交換記憶體的引用?Notelogind包含這樣的文件描述符。

EDIT1在停止 systemd-logind(本地 Xorg 通過死亡來響應)並重新啟動 Xorg 之後,我看到整個 6GB 的交換空間都被清除了。

第二次之後,我可以確認這是 systemd-logind 中的一個錯誤。 logind記得關閉它持有的 DRM fd 的副本,但它無法關閉保存在 PID1 中的副本(用於支持 logind 的“無縫”重啟):

$ sudo lsof /dev/dri/card0 | grep systemd
[sudo] password for alan-sysop: 
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
     Output information may be incomplete.
systemd      1       root   16u   CHR  226,0      0t0 14690 /dev/dri/card0
systemd      1       root   87u   CHR  226,0      0t0 14690 /dev/dri/card0
systemd      1       root  101u   CHR  226,0      0t0 14690 /dev/dri/card0
systemd      1       root  106u   CHR  226,0      0t0 14690 /dev/dri/card0
systemd      1       root  110u   CHR  226,0      0t0 14690 /dev/dri/card0
systemd-l  860       root   21u   CHR  226,0      0t0 14690 /dev/dri/card0
systemd-l  860       root   25u   CHR  226,0      0t0 14690 /dev/dri/card0

這感覺很像一個已知的錯誤,應該已經在 systemd 的 v238 中修復


實際上,每次我登錄和退出 GNOME 時,logind 似乎都會以這種方式洩漏 DRM fd。大概只有當顯示伺服器不干淨地關閉時,此錯誤才會變得明顯,因此它們沒有機會釋放附加到其 DRM fd 的緩衝區。

EDIT2:我是否正確猜測圖形設備(DRM)的文件描述符可以包含對可交換記憶體的引用?注意 logind 持有這樣的文件描述符。

回答:是的。

菲利普

SHMEM 文件節點用作可交換緩衝區對象的備份儲存。

https://www.kernel.org/doc/html/v4.15/gpu/drm-mm.html

據我了解,這裡的“SHMEM 文件節點”與 tmpfs 文件/memfd 的工作完全相同。上面的引用是關於“GEM 緩衝區對象”…

mmap 系統呼叫不能直接用於映射 GEM 對象,因為它們沒有自己的文件句柄。目前有兩種替代方法可以將 GEM 對象映射到使用者空間……第二種方法使用 DRM 文件句柄上的 mmap 系統呼叫。

https://01.org/linuxgraphics/gfx-docs/drm/drm-memory-management.html#id-1.3.4.6.6.8

**結論:**有人真的應該仔細檢查 logind 中的目前程式碼,因為它與文件句柄的關閉有關:)。


附錄:如何嘗試排除 memfds

有沒有人有一個很好的方法來檢查 memfds 的記憶體使用情況?

memfds 的記憶體使用情況可以stat --dereference通過. 要麼是文件描述符,要麼 - 你忘記了 -記憶體映射對象。du -D``/proc/$PID``fd/$FD``map_files/...

我對此並沒有非常好的便利,但您至少可以搜尋最大的單個 FD 或映射文件。(下面的範例不是額外的證據;它是在 6GB 的交換使用量消失後拍攝的)。

$ sudo du -aLh /proc/*/map_files/ /proc/*/fd/ | sort -h | tail -n 10
du: cannot access '/proc/self/fd/3': No such file or directory
du: cannot access '/proc/thread-self/fd/3': No such file or directory
108M    /proc/10397/map_files/7f1e141b4000-7f1e1ad84000
111M    /proc/14862/map_files/
112M    /proc/10397/map_files/
113M    /proc/18324/map_files/7efdda2fb000-7efddaafb000
121M    /proc/18324/map_files/7efdea2fb000-7efdeaafb000
129M    /proc/18324/map_files/7efdc82fb000-7efdc8afb000
129M    /proc/18324/map_files/7efdd42fb000-7efdd4afb000
129M    /proc/18324/map_files/7efde52fb000-7efde5afb000
221M    /proc/26350/map_files/
3.9G    /proc/18324/map_files/

$ ps -x -q 18324
 PID TTY      STAT   TIME COMMAND
18324 pts/1    S+     0:00 journalctl -b -f

$ ps -x -q 26350
 PID TTY      STAT   TIME COMMAND
26350 ?        Sl     4:35 /usr/lib64/firefox/firefox

$ sudo ls -l /proc/18324/map_files/7efde52fb000-7efde5afb000
lr--------. 1 root root 64 Mar 19 00:32 /proc/18324/map_files/7efde52fb000-7efde5afb000
-> /var/log/journal/f211872a957d411a9315fd911006ef03/user-1001@c3f024d4b01f4531b9b69e0876e42af8-00000000002e2acf-00055bbea4d9059d.journal

引用自:https://unix.stackexchange.com/questions/431982