decoratorを使うのが一番簡単だと思いました(処理を追いにくく悪評も多い気がしますが)。
コード
python
1import os
2import gc
3import psutil
4
5def print_memories():
6 print(psutil.Process(os.getpid()).memory_info())
7
8def gc_when_returned(func):
9 def wrapper(*args, **kwargs):
10 func(*args, **kwargs)
11 gc.collect()
12 print("gc collected.")
13 return wrapper
14
15def hoge():
16 print("hoge()")
17 o = [x for x in range(1024 * 1024)]
18 print_memories()
19
20@gc_when_returned
21def hoge_with_gc():
22 print("hoge_with_gc()")
23 o = [x for x in range(1024 * 1024)]
24 print_memories()
25
26print_memories()
27hoge()
28print_memories()
29hoge_with_gc()
30print_memories()
※psutilはpipで入れる必要があります
結果
うちの環境(ubuntu 20.04 python3.8.10)だと実行結果は以下のようになります。
text
1pmem(rss=12230656, vms=22401024, shared=6459392, text=2863104, lib=0, data=5971968, dirty=0)
2hoge()
3pmem(rss=54915072, vms=65384448, shared=6602752, text=2863104, lib=0, data=48955392, dirty=0)
4pmem(rss=12750848, vms=22605824, shared=6602752, text=2863104, lib=0, data=6176768, dirty=0)
5hoge_with_gc()
6pmem(rss=54648832, vms=68108288, shared=6602752, text=2863104, lib=0, data=51679232, dirty=0)
7gc collected.
8pmem(rss=20930560, vms=34029568, shared=6602752, text=2863104, lib=0, data=17600512, dirty=0)
今回の例を今回の環境で見ると、普通に戻っただけでも開放されているので、あまり期待した効果はないようです。他の環境(処理系/バージョン/プラットフォーム)でどうなるかは未知数なので、能動的なgc自体に意味がないかどうかは分かりません。
注意
gcは基本的に自動で行われますが、任意のタイミングで実施できます。個人的に考えている、能動的なgcの主な使用用途としては、大きなメモリを使った後長く忙しい処理が入るとき、その直前に確実にメモリを空けておきたいとか、メモリの少ない環境でこまめに手動でgcしておきたいとか(パラメータでも調整できるかも)、でしょうか。いずれにしても比較的負荷の高い作業なことに注意です。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。