
最好的 Hackaday 帖子是那些存在一些无法克服的问题,并通过对问题的深入分析和创造力设计出优雅的解决方案的帖子。这不是这些帖子之一。我相信您对位腐烂很熟悉。你知道,有些东西可以工作很长时间,然后,没有明显的原因,就停止工作了。好吧,这一直困扰着我,并且缺乏时间来寻找创造性的、优雅的解决方案,我决定用虚拟电锯来攻击它。
这一切都始于2022 年一篇关于使用 autokey 的 Linux 赋。
问题
我使用 autokey 在 Web 浏览器和某些其他程序中提供 emacs 风格的击键。它拦截击键并将其转换为其他击键。问题是,当前的 Linux 社区讨厌 autokey。嗯,这并不完全正确。他们只是更爱韦兰。我不会从 X11 切换的一个原因是我还没有找到一种方法来执行像使用自动键一样的操作。但由于大多数当权者都认为 X11 不好而 Wayland 好,X11 的开发开始出现裂缝。
特别是,autokey 不再位于我的发行版的正常存储库中(KDE Neon)。当然,我自己安装了最新版本。我完全有能力做到这一点,甚至可以从源代码构建。但最近,我注意到我的电脑挂起,尤其是在睡了很长时间之后。另外,过了很长一段时间,我注意到自动键就停止工作了。它正在运行但无法正常工作,我必须重新启动它。发生这种情况时,内存消耗似乎很高。
你知道是怎么回事。你的系统有一些怪癖;你只是和他们一起生活一段时间。但最终这些剪纸会加起来。我最终决定我需要解决这个问题。但我真的没有时间去调试自动键,尤其是当问题需要几个小时才能显现出来时。
电锯
我先说一下:找到内存泄漏是正确的做法。使用调试符号构建。运行代码并在问题出现时进行探测。尝试找出 X11、evdev 以及它使用的任何其他骗术的组合导致了这个故障。
但谁有时间这么做呢?我决定不直接启动自动键,而是启动一个包装脚本。我已经从 KDE 会话中删除了自动密钥,这样我就不会尝试自己启动它,然后让系统重新启动它。但现在我运行包装器而不是自动键。
那么包装器有什么作用呢?它监视自动键的内存消耗。果然,它一直在上涨一点点。当脚本发现它超过阈值时,它会杀死它并重新启动它。如果自动键死机,它也会重新启动,但我很少看到这种情况。
内存是什么意思?
问题是,如何确定进程使用了多少内存?是它拥有的物理页数量吗?虚拟空间?那么共享库呢?在这种情况下,我并不关心,只要我能看到一个一直在上升的数字即可。
/proc 文件系统为每个 PID 都有一个目录,其中包含大量信息。其中之一是记忆的统计。如果你查看 /proc/$PID/smaps 中的某个程序,你会看到类似这样的内容:
00400000-00420000 r--p 00000000 fd:0e 238814592 /usr/bin/python3.12 大小:128 kB 内核页面大小:4 kB MMU页面大小:4 kB RSS:128 kB 附:25 kB Pss_Dirty:0 kB 共享_清理:128 kB 共享_脏:0 kB 私人_清洁:0 kB Private_Dirty:0 kB 参考文献:128 kB 匿名:0 kB 密钥管理:0 KB 懒惰自由:0 kB AnonHugePages:0 kB ShmemPmd映射:0 kB 文件 Pmd 映射:0 kB Shared_Hugetlb:0 kB Private_Hugetlb:0 kB 交换:0 kB 交换Pss:0 kB 锁定:0 kB THP 合格: 0 VmFlags:rd mr mw me sd 00420000-00703000 r-xp 00020000 fd:0e 238814592 /usr/bin/python3.12 大小:2956 kB 内核页面大小:4 kB MMU页面大小:4 kB RSS:2944 kB 附:595 kB Pss_Dirty:0 kB 共享_清理:2944 kB 共享_脏:0 kB 私人_清洁:0 kB Private_Dirty:0 kB 。 。 。
请注意,每个可执行文件和共享对象都有一个部分以及大量信息。您可以将每个模块的所有 PSS(比例集大小)数字加在一起,如下所示(以及其他方式):
猫 /proc/$PID/smaps | grep -i 附ss | awk '{总计+=$2} END { 打印总计}'
建造电锯
因此,有了该代码,就可以很容易地运行该程序,看看它是否占用了太多内存,如果是,则重新启动它。我还添加了一些可选的调试代码。
#!/bin/bash #- 运行自动键,如果它太大就杀死它 #- 什么太大了? $MLIMIT 最大限额=500000 #- 检查的频率(秒) 投票=10 #- 如果需要的话打印调试信息 函数 pdebug { #- 如果您不想调试,请注释掉。如果你这样做就离开 #- 回显 $1 $2 $3 $4 } while true #永远做 做 PID=$(pgrep autokey-qt) # 查找 autokey pdebug "PID",$PID 如果 [ ! -z "$PID" ] # 如果存在 然后 # 获取内存大小 PSS=$(cat /proc/$PID/smaps | grep -i pss | awk '{总计+=$2} END { 打印总计}') pdebug“PSS”,$PSS 回声 $PSS >>/tmp/autokey-current.log #太大? 如果 [“$PSS”-gt“$MLIMIT”] 然后 pdebug“杀死” echo 被杀死 >>/tmp/autokey-current.log # 在我们开始另一个之前保存旧日志 cp /tmp/autokey-current.log /tmp/autokey-$PID.log 杀死$PID PID= 睡觉2 菲 菲 如果 [ -z $PID ] 然后 # 如果死了,重新启动 pdebug“启动” autokey-qt & 2>&1 >/tmp/autokey-current.log 菲 pdebug“睡眠” 睡眠$POLL 完毕
在实践中,您可能希望删除保存旧日志的cp
命令,但在排除故障时,最好了解进程被终止的频率。用一个大数字运行一次让我知道 PSS 约为 140,000,但每 10 秒就会上升。所以当达到500,000时,就完成了。这似乎运作良好。显然,无论你做什么,你都会调整数字。
坏电锯
有很多方法可以做到这一点。例如, systemd 计时器。甚至可能是一个 cgroup。但这很有效,而且只花了几分钟。当然,电锯对于切割 2×4 的尺寸来说非常困难,但话又说回来,它会像热刀切黄油一样切开它。
我确实考虑过定期终止 autokey 并重新启动它。问题是我有时工作时间很奇怪,这意味着我必须做一些事情,比如将它绑定到屏幕保护程序。但我同意有很多方法可以做到这一点,包括停止使用自动键。你的解决方案是什么?请在评论中告诉我们。你曾用过这么肮脏的伎俩吗?
原文: https://hackaday.com/2025/04/14/linux-fu-stopping-a-runaway/