"tracemalloc" --- メモリ割り当ての追跡
**************************************

Added in version 3.4.

**ソースコード:** Lib/tracemalloc.py

======================================================================

tracemallocモジュールは、Python が割り当てたメモリブロックをトレースす
るためのデバッグツールです。このモジュールは以下の情報を提供します。

* オブジェクトが割り当てられた場所のトレースバック

* ファイル名ごと、及び行ごとに割り当てられたメモリブロックの以下の統計
  を取ります：総サイズ、ブロック数、割り当てられたブロックの平均サイズ

* メモリリークを検出するために2つのスナップショットの差を計算します。

Python が割り当てたメモリブロックの大半をトレースするには、
"PYTHONTRACEMALLOC" 環境変数を "1" に設定して可能な限り早くモジュール
を開始させるか、"-X" "tracemalloc" コマンドラインオプションを使用して
ください。実行時に "tracemalloc.start()" を呼んで Python のメモリ割り
当てのトレースを開始することが出来ます。

デフォルトでは、割り当てられたメモリブロック1つのトレースは最新1フレー
ムを保存します。開始時に25フレームを保存するには、"PYTHONTRACEMALLOC"
環境変数を "25" に設定するか、"-X" "tracemalloc=25" コマンドラインオプ
ションを使用してください。


使用例
======


上位10を表示する
----------------

最も多くのメモリを割り当てているファイル10を表示します:

   import tracemalloc

   tracemalloc.start()

   # ... run your application ...

   snapshot = tracemalloc.take_snapshot()
   top_stats = snapshot.statistics('lineno')

   print("[ Top 10 ]")
   for stat in top_stats[:10]:
       print(stat)

Python テストスイートの出力例です:

   [ Top 10 ]
   <frozen importlib._bootstrap>:716: size=4855 KiB, count=39328, average=126 B
   <frozen importlib._bootstrap>:284: size=521 KiB, count=3199, average=167 B
   /usr/lib/python3.4/collections/__init__.py:368: size=244 KiB, count=2315, average=108 B
   /usr/lib/python3.4/unittest/case.py:381: size=185 KiB, count=779, average=243 B
   /usr/lib/python3.4/unittest/case.py:402: size=154 KiB, count=378, average=416 B
   /usr/lib/python3.4/abc.py:133: size=88.7 KiB, count=347, average=262 B
   <frozen importlib._bootstrap>:1446: size=70.4 KiB, count=911, average=79 B
   <frozen importlib._bootstrap>:1454: size=52.0 KiB, count=25, average=2131 B
   <string>:5: size=49.7 KiB, count=148, average=344 B
   /usr/lib/python3.4/sysconfig.py:411: size=48.0 KiB, count=1, average=48.0 KiB

Python がモジュールから "4855 KiB" のデータ (バイトコードで定数) を読
み込んでいることと、"collections" モジュールが "namedtuple" 型をビルド
するのに "244 KiB" を割り当てていることが分かります。

オプションの詳細については "Snapshot.statistics()" を参照してください
。


差を計算する
------------

スナップショットを2つ取り、差を表示します:

   import tracemalloc
   tracemalloc.start()
   # ... start your application ...

   snapshot1 = tracemalloc.take_snapshot()
   # ... call the function leaking memory ...
   snapshot2 = tracemalloc.take_snapshot()

   top_stats = snapshot2.compare_to(snapshot1, 'lineno')

   print("[ Top 10 differences ]")
   for stat in top_stats[:10]:
       print(stat)

Python テストスイートのテストを実行する前後の出力例です:

   [ Top 10 differences ]
   <frozen importlib._bootstrap>:716: size=8173 KiB (+4428 KiB), count=71332 (+39369), average=117 B
   /usr/lib/python3.4/linecache.py:127: size=940 KiB (+940 KiB), count=8106 (+8106), average=119 B
   /usr/lib/python3.4/unittest/case.py:571: size=298 KiB (+298 KiB), count=589 (+589), average=519 B
   <frozen importlib._bootstrap>:284: size=1005 KiB (+166 KiB), count=7423 (+1526), average=139 B
   /usr/lib/python3.4/mimetypes.py:217: size=112 KiB (+112 KiB), count=1334 (+1334), average=86 B
   /usr/lib/python3.4/http/server.py:848: size=96.0 KiB (+96.0 KiB), count=1 (+1), average=96.0 KiB
   /usr/lib/python3.4/inspect.py:1465: size=83.5 KiB (+83.5 KiB), count=109 (+109), average=784 B
   /usr/lib/python3.4/unittest/mock.py:491: size=77.7 KiB (+77.7 KiB), count=143 (+143), average=557 B
   /usr/lib/python3.4/urllib/parse.py:476: size=71.8 KiB (+71.8 KiB), count=969 (+969), average=76 B
   /usr/lib/python3.4/contextlib.py:38: size=67.2 KiB (+67.2 KiB), count=126 (+126), average=546 B

Python がモジュールデータ "8173 KiB" (バイトコードと定数) を読み込み、
前回スナップショットを取ったとき、すなわちテストの前に読み込んだ量より
"4428 KiB" 多いということが分かります。 同様に、 "linecache" モジュー
ルはトレースバックの書式化に Python ソースコード "940 KiB" をキャッシ
ュし、その全ては前回のスナップショットの後に行われたことが分かります。

システムに空きメモリがほとんどない場合、スナップショットをオフラインで
解析するための "Snapshot.dump()" メソッドを使用して、スナップショット
をディスクに書き込むことが出来ます。 そして "Snapshot.load()" メソッド
を使用してスナップショットを再読み込みします。


メモリブロックのトレースバックを取得する
----------------------------------------

最大のメモリブロックのトレースバックを表示するコードです:

   import tracemalloc

   # Store 25 frames
   tracemalloc.start(25)

   # ... run your application ...

   snapshot = tracemalloc.take_snapshot()
   top_stats = snapshot.statistics('traceback')

   # pick the biggest memory block
   stat = top_stats[0]
   print("%s memory blocks: %.1f KiB" % (stat.count, stat.size / 1024))
   for line in stat.traceback.format():
       print(line)

Python テストスイートの出力例です (トレースバックは 25 フレームに制限
されています):

   903 memory blocks: 870.1 KiB
     File "<frozen importlib._bootstrap>", line 716
     File "<frozen importlib._bootstrap>", line 1036
     File "<frozen importlib._bootstrap>", line 934
     File "<frozen importlib._bootstrap>", line 1068
     File "<frozen importlib._bootstrap>", line 619
     File "<frozen importlib._bootstrap>", line 1581
     File "<frozen importlib._bootstrap>", line 1614
     File "/usr/lib/python3.4/doctest.py", line 101
       import pdb
     File "<frozen importlib._bootstrap>", line 284
     File "<frozen importlib._bootstrap>", line 938
     File "<frozen importlib._bootstrap>", line 1068
     File "<frozen importlib._bootstrap>", line 619
     File "<frozen importlib._bootstrap>", line 1581
     File "<frozen importlib._bootstrap>", line 1614
     File "/usr/lib/python3.4/test/support/__init__.py", line 1728
       import doctest
     File "/usr/lib/python3.4/test/test_pickletools.py", line 21
       support.run_doctest(pickletools)
     File "/usr/lib/python3.4/test/regrtest.py", line 1276
       test_runner()
     File "/usr/lib/python3.4/test/regrtest.py", line 976
       display_failure=not verbose)
     File "/usr/lib/python3.4/test/regrtest.py", line 761
       match_tests=ns.match_tests)
     File "/usr/lib/python3.4/test/regrtest.py", line 1563
       main()
     File "/usr/lib/python3.4/test/__main__.py", line 3
       regrtest.main_in_temp_cwd()
     File "/usr/lib/python3.4/runpy.py", line 73
       exec(code, run_globals)
     File "/usr/lib/python3.4/runpy.py", line 160
       "__main__", fname, loader, pkg_name)

We can see that the most memory was allocated in the "importlib"
module to load data (bytecode and constants) from modules: "870.1
KiB". The traceback is where the "importlib" loaded data most
recently: on the "import pdb" line of the "doctest" module. The
traceback may change if a new module is loaded.


top を整形化する
----------------

"<frozen importlib._bootstrap>" および "<unknown>" ファイルを無視して
、 メモリ割り当て量の上位10を整形化して表示するコードです:

   import linecache
   import os
   import tracemalloc

   def display_top(snapshot, key_type='lineno', limit=10):
       snapshot = snapshot.filter_traces((
           tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
           tracemalloc.Filter(False, "<unknown>"),
       ))
       top_stats = snapshot.statistics(key_type)

       print("Top %s lines" % limit)
       for index, stat in enumerate(top_stats[:limit], 1):
           frame = stat.traceback[0]
           print("#%s: %s:%s: %.1f KiB"
                 % (index, frame.filename, frame.lineno, stat.size / 1024))
           line = linecache.getline(frame.filename, frame.lineno).strip()
           if line:
               print('    %s' % line)

       other = top_stats[limit:]
       if other:
           size = sum(stat.size for stat in other)
           print("%s other: %.1f KiB" % (len(other), size / 1024))
       total = sum(stat.size for stat in top_stats)
       print("Total allocated size: %.1f KiB" % (total / 1024))

   tracemalloc.start()

   # ... run your application ...

   snapshot = tracemalloc.take_snapshot()
   display_top(snapshot)

Python テストスイートの出力例です:

   Top 10 lines
   #1: Lib/base64.py:414: 419.8 KiB
       _b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
   #2: Lib/base64.py:306: 419.8 KiB
       _a85chars2 = [(a + b) for a in _a85chars for b in _a85chars]
   #3: collections/__init__.py:368: 293.6 KiB
       exec(class_definition, namespace)
   #4: Lib/abc.py:133: 115.2 KiB
       cls = super().__new__(mcls, name, bases, namespace)
   #5: unittest/case.py:574: 103.1 KiB
       testMethod()
   #6: Lib/linecache.py:127: 95.4 KiB
       lines = fp.readlines()
   #7: urllib/parse.py:476: 71.8 KiB
       for a in _hexdig for b in _hexdig}
   #8: <string>:5: 62.0 KiB
   #9: Lib/_weakrefset.py:37: 60.0 KiB
       self.data = set()
   #10: Lib/base64.py:142: 59.8 KiB
       _b32tab2 = [a + b for a in _b32tab for b in _b32tab]
   6220 other: 3602.8 KiB
   Total allocated size: 5303.1 KiB

オプションの詳細については "Snapshot.statistics()" を参照してください
。


Record the current and peak size of all traced memory blocks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The following code computes two sums like "0 + 1 + 2 + ..."
inefficiently, by creating a list of those numbers. This list consumes
a lot of memory temporarily. We can use "get_traced_memory()" and
"reset_peak()" to observe the small memory usage after the sum is
computed as well as the peak memory usage during the computations:

   import tracemalloc

   tracemalloc.start()

   # Example code: compute a sum with a large temporary list
   large_sum = sum(list(range(100000)))

   first_size, first_peak = tracemalloc.get_traced_memory()

   tracemalloc.reset_peak()

   # Example code: compute a sum with a small temporary list
   small_sum = sum(list(range(1000)))

   second_size, second_peak = tracemalloc.get_traced_memory()

   print(f"{first_size=}, {first_peak=}")
   print(f"{second_size=}, {second_peak=}")

出力:

   first_size=664, first_peak=3592984
   second_size=804, second_peak=29704

Using "reset_peak()" ensured we could accurately record the peak
during the computation of "small_sum", even though it is much smaller
than the overall peak size of memory blocks since the "start()" call.
Without the call to "reset_peak()", "second_peak" would still be the
peak from the computation "large_sum" (that is, equal to
"first_peak"). In this case, both peaks are much higher than the final
memory usage, and which suggests we could optimise (by removing the
unnecessary call to "list", and writing "sum(range(...))").


API
===


関数
----

tracemalloc.clear_traces()

   Python が割り当てたメモリブロックのトレースを消去します。

   "stop()" を参照してください。

tracemalloc.get_object_traceback(obj)

   Get the traceback where the Python object *obj* was allocated.
   Return a "Traceback" instance, or "None" if the "tracemalloc"
   module is not tracing memory allocations or did not trace the
   allocation of the object.

   "gc.get_referrers()" や "sys.getsizeof()" 関数も参照してください。

tracemalloc.get_traceback_limit()

   トレースのトレースバック内に格納されている最大フレーム数を取得しま
   す。

   The "tracemalloc" module must be tracing memory allocations to get
   the limit, otherwise an exception is raised.

   "start()" 関数で上限を設定します。

tracemalloc.get_traced_memory()

   Get the current size and peak size of memory blocks traced by the
   "tracemalloc" module as a tuple: "(current: int, peak: int)".

tracemalloc.reset_peak()

   Set the peak size of memory blocks traced by the "tracemalloc"
   module to the current size.

   Do nothing if the "tracemalloc" module is not tracing memory
   allocations.

   This function only modifies the recorded peak size, and does not
   modify or clear any traces, unlike "clear_traces()". Snapshots
   taken with "take_snapshot()" before a call to "reset_peak()" can be
   meaningfully compared to snapshots taken after the call.

   "get_traced_memory()" も参照してください。

   Added in version 3.9.

tracemalloc.get_tracemalloc_memory()

   Get the memory usage in bytes of the "tracemalloc" module used to
   store traces of memory blocks. Return an "int".

tracemalloc.is_tracing()

   "True" if the "tracemalloc" module is tracing Python memory
   allocations, "False" otherwise.

   "start()" ならびに "stop()" 関数も参照してください。

tracemalloc.start(nframe: int = 1)

   Python のメモリ割り当てのトレースを開始します: Python メモリアロケ
   ータにフックします。 トレースの収集されたトレースバックは *nframe*
   フレームに制限されます。 デフォルトでは、あるブロックのトレースは最
   新のフレームのみを保存します、つまり上限は "1" です。 *nframe* は
   "1" 以上でなければなりません。

   You can still read the original number of total frames that
   composed the traceback by looking at the "Traceback.total_nframe"
   attribute.

   "1" より多くのフレームを保存するのは "'traceback'" でグループ化され
   た統計や累積的な統計を計算する場合にのみ有用です。
   "Snapshot.compare_to()" および "Snapshot.statistics()" メソッドを参
   照してください。

   Storing more frames increases the memory and CPU overhead of the
   "tracemalloc" module. Use the "get_tracemalloc_memory()" function
   to measure how much memory is used by the "tracemalloc" module.

   "PYTHONTRACEMALLOC" 環境変数 ("PYTHONTRACEMALLOC=NFRAME") と  "-X"
   "tracemalloc=NFRAME" コマンドラインオプションを使って実行開始時にト
   レースを始めることが出来ます。

   "stop()"、"is_tracing()"、"get_traceback_limit()" 関数を参照してく
   ださい。

tracemalloc.stop()

   Python のメモリ割り当てのトレースを停止します。つまり、Python のメ
   モリ割り当てへのフックをアンインストールします。 Python が割り当て
   たメモリブロックについてこれまで集めたトレースも全てクリアします。

   トレースが全部クリアされる前にスナップショットを取りたい場合は
   "take_snapshot()" 関数を呼んでください。

   "start()"、"is_tracing()"、"clear_traces()" 関数も参照してください
   。

tracemalloc.take_snapshot()

   Python が割り当てたメモリブロックのトレースのスナップショットを取り
   ます。新しい "Snapshot" インスタンスを返します。

   The snapshot does not include memory blocks allocated before the
   "tracemalloc" module started to trace memory allocations.

   トレースのトレースバックは "get_traceback_limit()" フレームに制限さ
   れています。より多くのフレームを保存するには "start()" 関数の
   *nframe* 引数を使用してください。

   The "tracemalloc" module must be tracing memory allocations to take
   a snapshot, see the "start()" function.

   "get_object_traceback()" 関数を参照してください。


DomainFilter
------------

class tracemalloc.DomainFilter(inclusive: bool, domain: int)

   Filter traces of memory blocks by their address space (domain).

   Added in version 3.6.

   inclusive

      If *inclusive* is "True" (include), match memory blocks
      allocated in the address space "domain".

      If *inclusive* is "False" (exclude), match memory blocks not
      allocated in the address space "domain".

   domain

      Address space of a memory block ("int"). Read-only property.


Filter
------

class tracemalloc.Filter(inclusive: bool, filename_pattern: str, lineno: int = None, all_frames: bool = False, domain: int = None)

   メモリブロックのトレースをフィルターします。

   *filename_pattern* のシンタックスについては "fnmatch.fnmatch()" 関
   数を参照してください。"'.pyc'" 拡張子は "'.py'" に置換されます。

   例:

   * "Filter(True, subprocess.__file__)" は "subprocess" モジュールの
     みを含みます

   * "Filter(False, tracemalloc.__file__)" excludes traces of the
     "tracemalloc" module

   * "Filter(False, "<unknown>")" は空のトレースバックを除外します

   バージョン 3.5 で変更: "'.pyo'" ファイル拡張子が "'.py'" に置換され
   ることはもうありません。

   バージョン 3.6 で変更: "domain" 属性が追加されました。

   domain

      Address space of a memory block ("int" or "None").

      tracemalloc uses the domain "0" to trace memory allocations made
      by Python. C extensions can use other domains to trace other
      resources.

   inclusive

      If *inclusive* is "True" (include), only match memory blocks
      allocated in a file with a name matching "filename_pattern" at
      line number "lineno".

      If *inclusive* is "False" (exclude), ignore memory blocks
      allocated in a file with a name matching "filename_pattern" at
      line number "lineno".

   lineno

      フィルタの行番号です ("int")。*lineno* が "None" の場合フィルタ
      はあらゆる行番号にマッチします。

   filename_pattern

      フィルタのファイル名のパターンです ("str")。読み出し専用のプロパ
      ティです。

   all_frames

      *all_frames* が "True" の場合トレースバックの全てのフレームをチ
      ェックします。*all_frames* が "False" の場合最新のフレームをチェ
      ックします。

      トレースバックの上限が "1" の場合この属性の影響はありません。
      "get_traceback_limit()" 関数と "Snapshot.traceback_limit" 属性を
      参照してください。


Frame
-----

class tracemalloc.Frame

   トレースバックのフレームです。

   "Traceback" クラスは "Frame" インスタンスのシークエンスです。

   filename

      ファイル名 ("str")。

   lineno

      行番号 ("int")。


Snapshot
--------

class tracemalloc.Snapshot

   Python が割り当てたメモリブロックのトレースのスナップショットです。

   "take_snapshot()" 関数はスナップショットのインスタンスを作ります。

   compare_to(old_snapshot: Snapshot, key_type: str, cumulative: bool = False)

      古いスナップショットとの差を計算します。 *key_type* でグループ化
      された "StatisticDiff" インスタンスのソート済みリストとして統計
      を取得します。

      *key_type* および *cumulative* 引数については
      "Snapshot.statistics()" メソッドを参照してください。

      結果は降順でソートされます: キーは "StatisticDiff.size_diff" の
      絶対値、 "StatisticDiff.size"、 "StatisticDiff.count_diff" の絶
      対置、 "Statistic.count"、そして "StatisticDiff.traceback" です
      。

   dump(filename)

      スナップショットをファイルに書き込みます。

      スナップショットをリロードするには "load()" を使用します。

   filter_traces(filters)

      Create a new "Snapshot" instance with a filtered "traces"
      sequence, *filters* is a list of "DomainFilter" and "Filter"
      instances.  If *filters* is an empty list, return a new
      "Snapshot" instance with a copy of the traces.

      All inclusive filters are applied at once, a trace is ignored if
      no inclusive filters match it. A trace is ignored if at least
      one exclusive filter matches it.

      バージョン 3.6 で変更: "DomainFilter" instances are now also
      accepted in *filters*.

   classmethod load(filename)

      スナップショットをファイルからロードします。

      "dump()" を参照してください。

   statistics(key_type: str, cumulative: bool = False)

      *key_type* でグループ化された "Statistic" インスタンスのソート済
      みリストとして統計を取得します:

      +-----------------------+--------------------------+
      | key_type              | description              |
      |=======================|==========================|
      | "'filename'"          | ファイル名               |
      +-----------------------+--------------------------+
      | "'lineno'"            | ファイル名と行番号       |
      +-----------------------+--------------------------+
      | "'traceback'"         | traceback                |
      +-----------------------+--------------------------+

      If *cumulative* is "True", cumulate size and count of memory
      blocks of all frames of the traceback of a trace, not only the
      most recent frame. The cumulative mode can only be used with
      *key_type* equal to "'filename'" and "'lineno'".

      結果は降順でソートされます: キーは "Statistic.size",
      "Statistic.count", "Statistic.traceback" です。

   traceback_limit

      "traces" のトレースバック内に保存されるフレーム数の最大値です。
      スナップショットが取られたときの "get_traceback_limit()" の結果
      です。

   traces

      Python が割り当てた全メモリブロックのトレースで、 "Trace" インス
      タンスのシークェンスです。

      シークェンスの順序は未定義です。統計のソート済みリストを取得する
      には "Snapshot.statistics()" を使用してください。


Statistic
---------

class tracemalloc.Statistic

   メモリ割り当ての統計です。

   "Snapshot.statistics()" は "Statistic" インスタンスの一覧を返します
   。

   "StatisticDiff" クラスも参照してください。

   count

      メモリブロック数 ("int")。

   size

      メモリブロックのバイト単位の総サイズ ("int")。

   traceback

      メモリブロックが割り当てられているトレースバック。"Traceback" イ
      ンスタンス。


StatisticDiff
-------------

class tracemalloc.StatisticDiff

   新旧 "Snapshot" インスタンスのメモリ割り当ての統計差です。

   "Snapshot.compare_to()" は "StatisticDiff" インスタンスのリストを返
   します。 "Statistic" クラスも参照してください。

   count

      新しいスナップショット内のメモリブロックの数 ("int") です。新し
      いスナップショット内でメモリブロックが解放された場合は "0" です
      。

   count_diff

      新旧スナップショットのメモリブロック数の差 ("int") です。メモリ
      ブロックが新しいスナップショット内で割り当てられた場合は "0" で
      す。

   size

      新しいスナップショット内のメモリブロックのバイト単位での総サイズ
      ("int") です。新しいスナップショット内でメモリブロックが解放され
      た場合は "0" です。

   size_diff

      新旧スナップショットのバイト単位での総サイズの差 ("int") です。
      メモリブロックが新しいスナップショット内で割り当てられた場合は
      "0" です。

   traceback

      メモリブロックが割り当てられたトレースバックで、 "Traceback" の
      インスタンスです。


Trace
-----

class tracemalloc.Trace

   メモリブロックをトレースします。

   "Snapshot.traces" 属性は "Trace" インスタンスのシークエンスです。

   バージョン 3.6 で変更: "domain" 属性が追加されました。

   domain

      Address space of a memory block ("int"). Read-only property.

      tracemalloc uses the domain "0" to trace memory allocations made
      by Python. C extensions can use other domains to trace other
      resources.

   size

      メモリブロックのバイト単位のサイズ ("int")。

   traceback

      メモリブロックが割り当てられているトレースバック。"Traceback" イ
      ンスタンス。


Traceback
---------

class tracemalloc.Traceback

   Sequence of "Frame" instances sorted from the oldest frame to the
   most recent frame.

   A traceback contains at least "1" frame. If the "tracemalloc"
   module failed to get a frame, the filename ""<unknown>"" at line
   number "0" is used.

   When a snapshot is taken, tracebacks of traces are limited to
   "get_traceback_limit()" frames. See the "take_snapshot()" function.
   The original number of frames of the traceback is stored in the
   "Traceback.total_nframe" attribute. That allows one to know if a
   traceback has been truncated by the traceback limit.

   The "Trace.traceback" attribute is a "Traceback" instance.

   バージョン 3.7 で変更: Frames are now sorted from the oldest to the
   most recent, instead of most recent to oldest.

   total_nframe

      Total number of frames that composed the traceback before
      truncation. This attribute can be set to "None" if the
      information is not available.

   バージョン 3.9 で変更: "Traceback.total_nframe" 属性が追加されまし
   た。

   format(limit=None, most_recent_first=False)

      Format the traceback as a list of lines. Use the "linecache"
      module to retrieve lines from the source code. If *limit* is
      set, format the *limit* most recent frames if *limit* is
      positive. Otherwise, format the "abs(limit)" oldest frames. If
      *most_recent_first* is "True", the order of the formatted frames
      is reversed, returning the most recent frame first instead of
      last.

      Similar to the "traceback.format_tb()" function, except that
      "format()" does not include newlines.

      以下はプログラム例です:

         print("Traceback (most recent call first):")
         for line in traceback:
             print(line)

      出力:

         Traceback (most recent call first):
           File "test.py", line 9
             obj = Object()
           File "test.py", line 12
             tb = tracemalloc.get_object_traceback(f())
