|
1 | 1 | # -*- encoding: utf-8 -*-
|
2 | 2 | import collections
|
| 3 | +import gc |
3 | 4 | import os
|
4 | 5 | import sys
|
5 | 6 | import threading
|
6 | 7 | import time
|
7 | 8 | import timeit
|
| 9 | +from types import FrameType |
8 | 10 | import typing
|
9 | 11 | import uuid
|
10 | 12 |
|
@@ -400,7 +402,7 @@ def test_exception_collection():
|
400 | 402 | assert e.sampling_period > 0
|
401 | 403 | assert e.thread_id == nogevent.thread_get_ident()
|
402 | 404 | assert e.thread_name == "MainThread"
|
403 |
| - assert e.frames == [(__file__, 394, "test_exception_collection", "")] |
| 405 | + assert e.frames == [(__file__, 396, "test_exception_collection", "")] |
404 | 406 | assert e.nframes == 1
|
405 | 407 | assert e.exc_type == ValueError
|
406 | 408 |
|
@@ -432,7 +434,7 @@ def test_exception_collection_trace(
|
432 | 434 | assert e.sampling_period > 0
|
433 | 435 | assert e.thread_id == nogevent.thread_get_ident()
|
434 | 436 | assert e.thread_name == "MainThread"
|
435 |
| - assert e.frames == [(__file__, 421, "test_exception_collection_trace", "")] |
| 437 | + assert e.frames == [(__file__, 423, "test_exception_collection_trace", "")] |
436 | 438 | assert e.nframes == 1
|
437 | 439 | assert e.exc_type == ValueError
|
438 | 440 | assert e.span_id == span.span_id
|
@@ -743,3 +745,23 @@ def _nothing():
|
743 | 745 | # assert (exact_time * 0.7) <= values.pop() <= (exact_time * 1.3)
|
744 | 746 |
|
745 | 747 | assert values.pop() > 0
|
| 748 | + |
| 749 | + |
| 750 | +@pytest.mark.skipif(sys.version_info < (3, 11, 0), reason="PyFrameObjects are lazy-created objects in Python 3.11+") |
| 751 | +def test_collect_ensure_all_frames_gc(): |
| 752 | + # Regression test for memory leak with lazy PyFrameObjects in Python 3.11+ |
| 753 | + def _foo(): |
| 754 | + pass |
| 755 | + |
| 756 | + r = recorder.Recorder() |
| 757 | + s = stack.StackCollector(r) |
| 758 | + |
| 759 | + with s: |
| 760 | + for _ in range(100): |
| 761 | + _foo() |
| 762 | + |
| 763 | + gc.collect() # Make sure we don't race with gc when we check frame objects |
| 764 | + frametype_objs = [obj for obj in gc.get_objects() if isinstance(obj, FrameType)] |
| 765 | + for obj in frametype_objs: |
| 766 | + # Ensure that all frames relating to _foo() have been gc'd already |
| 767 | + assert obj.f_code.co_name != "_foo" |
0 commit comments