t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

Linux Essentialの学習で得たヒントでラズパイのフリーズ原因を究明した話

このところ自作した目覚まし時計のフリーズに悩まされて来たのだが、ついにこれだという原因にたどり着いた。
thom.hateblo.jp

ヒントになったのがLinux Essentials試験の学習で得たメモリ管理まわり。
freeコマンドでメモリの状況を確認できるのでメモリリークを疑ってみようと思ったのだ。

試しに疑わしいスクリプトのcron実行を1分に1回の起動に変えてみたうえ、同じタイミングで毎回freeコマンドでメモリ容量を~/free.txtに書き込むようにしてみたところ次のような結果になった。

Thu  4 May 20:46:01 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432       93744      706304         964      131384      778148
Swap:         102396           0      102396

Thu  4 May 20:47:01 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432       99220      700760         964      131452      772652
Swap:         102396           0      102396

Thu  4 May 20:48:01 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432      104972      694472         964      131988      766880
Swap:         102396           0      102396

~中略~

Thu  4 May 21:03:01 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432      192092      605556         964      133784      679380
Swap:         102396           0      102396

これだ!
かなりのハイペースでメモリを食い続けている。

今回の犯人はwokeup.pyというスクリプト

前提として目覚まし時計は鳴るタイミングでcron起動されるalarm.pyと、常時起動のwokeup.pyで構成されている。
以前、常時起動の方が落ちていたことがあったのでいずれデーモン化しようと思っているのだが面倒なのでとりいそぎcronで毎時10分と40分に起動させている。
wokeup.pyはすでに起動しているwokeup.pyがあればpkillで落とすような仕様なので疑って無かったんだけど、psコマンドで確認してみると53件ものwokeupが起動中。まじか。

thom@alarm:~ $ ps aux | grep -c wokeup
53


とりいそぎ手動でpkillしたところ起動直後の基準まで落ち着いた。

thom@alarm:~ $ pkill wokeup
thom@alarm:~ $ ps aux | grep -c wokeup
1
thom@alarm:~ $ free
               total        used        free      shared  buff/cache   available
Mem:          931432       82632      714468         972      134332      788768
Swap:         102396           0      102396


wokeupスクリプト内で原因となっているのはこの部分。
要するにpkillに失敗しているらしい。

cmd = "sudo pkill wokeup"
proc = Popen(cmd.strip().split(" "))
proc.wait()
sp.setproctitle("wokeup")

そういえばalarm.pyも二重に鳴ったことがあってsudoを外したら上手く行ったんだった。
ひとつ思い当たる節はセキュリティ強化の為にsudo実行にパスワードを要求するように設定したこと。

スクリプト内のsudoならcronがうまく捌いてくれるかなと勝手に思い込んでいたんだけどダメだったみたいだ。
また、プロセスを終了させるpkillコマンドはroot権限じゃないと動かないという勘違いもあった。
自分で起動したプロセスなんだから、当然自分でpkillできるんだ。

コマンドの場所もsbinじゃなくてbinになっている。

thom@alarm:~ $ which pkill
/usr/bin/pkill


修正後の記録がこちら。

Thu  4 May 21:14:01 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432       90912      706048         972      134472      780488
Swap:         102396           0      102396

Thu  4 May 21:15:02 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432       85292      711736         964      134404      786152
Swap:         102396           0      102396

Thu  4 May 21:16:01 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432       85196      711728         964      134508      786268
Swap:         102396           0      102396

Thu  4 May 21:17:01 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432       88988      707948         964      134496      782508
Swap:         102396           0      102396

~中略~

Thu  4 May 21:23:01 JST 2023
               total        used        free      shared  buff/cache   available
Mem:          931432       87892      708996         964      134544      783620
Swap:         102396           0      102396

増減は見られるが修正前のように徐々に確実に減っていくということはない。

プロセスも確認してみた。周辺コマンドが表示されてしまっているもののwokeup本体は1つのみ。

thom@alarm:~ $ ps aux | grep wokeup
thom        1369  0.0  0.0   2064   468 ?        Ss   21:26   0:00 /bin/sh -c /home/thom/wokeup.py
thom        1371  2.0  1.0  24284  9680 ?        Sl   21:26   0:00 wokeup
thom        1377  0.0  0.0   5908   752 pts/0    S+   21:26   0:00 grep --color=auto wokeup

ということで恐らく解決。

これまでは馬鹿の一つ覚えとして落ちた後にひたすらsyslogを確認するということをしていたのだが知識不足で何が起きているのか分からず。

また、メモリの枯渇という概念を知識としては持っていたものの確認コマンドを知らなかったがためにメモリが枯渇しているという状況を想定すらできていなかった。

今回はLinux Essential試験に向けた網羅的な学習がヒントとなって解決できた形。

手段がなければ目的すら見えない。
これまでもいろんなところで実感してきたことだが今回も改めてそう認識した次第である。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。