初めに
職場でメモリリーク問題でトラブった調査してたら予想外の罠が見つかったので投稿します。
ちょっと乱文になると思うのですがご容赦ください。
環境
OS:Windows10
(base) PS C:\Users\95315> python -V
Python 3.6.10 :: Anaconda, Inc.
(base) PS C:\Users\95315> conda -V
conda 4.9.2
(base) PS C:\Users\95315>conda list
…
tk 8.6.8 hfa6e2cd_0
…
何がしたかったのか
https://tkdocs.com/tutorial/text.html
上記ページのExample: Logging Windowの節を参考して欲しいのですがロガーの内容を引っ張ってTk.textで表示するプログラムを作ってました。
要は下のコードです。
from tkinter import *
from tkinter import ttk
root = Tk()
log = Text(root, state='disabled', width=80, height=24, wrap='none')
log.grid()
def writeToLog(msg):
numlines = int(log.index('end - 1 line').split('.')[0])
log['state'] = 'normal'
if numlines==24:
log.delete(1.0, 2.0)
if log.index('end-1c')!='1.0':
log.insert('end', '\n')
log.insert('end', msg)
log['state'] = 'disabled'
何が起きたのか
ロガーの表示内容がある行数を超えると頭から削除してたんですが、それでもメモリ消費量がモリモリ増えて最終的にPC毎メモリ不足で落ちるというヤバげな挙動を示しており頭が痛い不具合が出ておりました…。
何がマズかったのか
色々探してたら以下のリファレンスがちょっと古いものの原因を記してました。
https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/text-undo-stack.html
The Text widget has a built-in mechanism that allows you to implement undo and redo operations that can cancel or >reinstate changes to the text within the widget.
要はTk.textはオプションでundo/redoスタックを持つよ。便利だね。
そうだね。勝手にONにしてスタック数無制限っぽい挙動をしなければ良かったね。
んでどう直したか
要はスタックを無効にするだけです。ぶっちゃけさっきのコードで言えばこう直します。
from tkinter import *
from tkinter import ttk
root = Tk()
log = Text(root, state='disabled', width=80, height=24, wrap='none',undo=False)
log.grid()
def writeToLog(msg):
numlines = int(log.index('end - 1 line').split('.')[0])
log['state'] = 'normal'
if numlines==24:
log.delete(1.0, 2.0)
if log.index('end-1c')!='1.0':
log.insert('end', '\n')
log.insert('end', msg)
log['state'] = 'disabled'
undo=Falseを追加するだけっすね。
俺はこの一行のためになんて時間を…
とまぁ割とえげつない話だったので記事にでもしとこう。そうでないと溜飲が下がらん。
というわけで記事にした次第です。
終わりに
公式からリンク張ってあるようなTKDocsでもこういうことがあるので、もはや何を信用してよいやら…
とりあえず一つのソースだけじゃなくて多角的に色々探るってのは大事だと思った次第です。
だからTkinterはクソとかそういうつもりはないです。というかPythonでGUIはどれも色々あるし標準で用意されてるTkinter使ってもいいんじゃないっすかね。
こういうトラブルがいくつか埋まってるのが気になるなら良さげなライブラリ使うのも一考ですが。
後はまぁ集合知でこういうトラブルあったよということはQiitaの記事にジャンジャン書いていいんじゃないでしょうか。
辛いトラブル引いたときはまぁQiitaに書くネタが出来たとでも思えば多少は気が晴れます。
んでここからが怖い話なんですが、メモリリーク要因はまだもう一件残っててそっちも探して潰さないといけないんですよ…フフフ
とまぁあまり引っかかる人はいないと思うので読み物としてそういうことあるんだと思っていただければ幸いです。
ここまで読んでくださりありがとうございました。