こんにちは、株式会社LIFULLの二宮です。去年のAdvent Calendarの埋め残しが心残りなので、小ネタですが投稿しておきます。
とある実装中に、変数のメモリの使用量を大まかに見積もる必要がありました。こちらの記事でも紹介されている通り、 sys.getsizeof
で変数のメモリ上のサイズを表示できるのですが、
import sys
print(sys.getsizeof({"key": "a"}))
# => 248
# 文字サイズが明らかに大きいのに同じ値が出てしまう
print(sys.getsizeof({"key": "a" * 10000}))
# => 248
というのも、Pythonの辞書の実体は「ハッシュテーブルにオブジェクトへの参照を保存したもの」で、中の文字列のメモリ上のサイズは考慮されません。このあたりの話は、こちらの記事が参考になると思います。
- Python: Create List of Object References - Stack Overflow
- [ruby] ポインタと参照とか知らなくても ruby は書ける、なんてことはない。
(日本語でいい記事がRubyのものしか見つけられませんでした。ただこのあたりの話はRubyもPythonも共通しています。)
中のオブジェクトのサイズまで考慮するには、公式ドキュメントのこちらのリンク先の記事を参考に実装する必要があります。
getsizeof()
を再帰的に使い、コンテナとその中身のサイズを割り出す例は、 再帰的なsizeof
のレシピ を参照してください。
ただ、私の場合は文字列のみが入った辞書(jsonにシリアライズ可能)で、概算値を知りたかっただけなので、こちらのStackOverflowの書き込みに従って、 json.dumps
の結果で済ませてしまいました。
>>> first = 'abc'*1000
>>> second = 'def'*1000
>>> my_dictionary = {'first': first, 'second': second}
>>> getsizeof(first)
3049
>>> getsizeof(second)
3049
>>> getsizeof(my_dictionary)
288
>>> getsizeof(json.dumps(my_dictionary))
6076
>>> size = getsizeof(my_dictionary)
>>> size += sum(map(getsizeof, my_dictionary.values())) + sum(map(getsizeof, my_dictionary.keys()))
>>> size
6495