Skip to content

Commit e560f90

Browse files
authored
bpo-40268: Move struct _gc_runtime_state to pycore_gc.h (GH-19515)
1 parent 4cf65a6 commit e560f90

File tree

6 files changed

+107
-105
lines changed

6 files changed

+107
-105
lines changed

Include/internal/pycore_gc.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,106 @@ typedef struct {
6363
#define _PyGC_SET_FINALIZED(o) \
6464
_PyGCHead_SET_FINALIZED(_Py_AS_GC(o))
6565

66+
67+
/* GC runtime state */
68+
69+
/* If we change this, we need to change the default value in the
70+
signature of gc.collect. */
71+
#define NUM_GENERATIONS 3
72+
/*
73+
NOTE: about untracking of mutable objects.
74+
75+
Certain types of container cannot participate in a reference cycle, and
76+
so do not need to be tracked by the garbage collector. Untracking these
77+
objects reduces the cost of garbage collections. However, determining
78+
which objects may be untracked is not free, and the costs must be
79+
weighed against the benefits for garbage collection.
80+
81+
There are two possible strategies for when to untrack a container:
82+
83+
i) When the container is created.
84+
ii) When the container is examined by the garbage collector.
85+
86+
Tuples containing only immutable objects (integers, strings etc, and
87+
recursively, tuples of immutable objects) do not need to be tracked.
88+
The interpreter creates a large number of tuples, many of which will
89+
not survive until garbage collection. It is therefore not worthwhile
90+
to untrack eligible tuples at creation time.
91+
92+
Instead, all tuples except the empty tuple are tracked when created.
93+
During garbage collection it is determined whether any surviving tuples
94+
can be untracked. A tuple can be untracked if all of its contents are
95+
already not tracked. Tuples are examined for untracking in all garbage
96+
collection cycles. It may take more than one cycle to untrack a tuple.
97+
98+
Dictionaries containing only immutable objects also do not need to be
99+
tracked. Dictionaries are untracked when created. If a tracked item is
100+
inserted into a dictionary (either as a key or value), the dictionary
101+
becomes tracked. During a full garbage collection (all generations),
102+
the collector will untrack any dictionaries whose contents are not
103+
tracked.
104+
105+
The module provides the python function is_tracked(obj), which returns
106+
the CURRENT tracking status of the object. Subsequent garbage
107+
collections may change the tracking status of the object.
108+
109+
Untracking of certain containers was introduced in issue #4688, and
110+
the algorithm was refined in response to issue #14775.
111+
*/
112+
113+
struct gc_generation {
114+
PyGC_Head head;
115+
int threshold; /* collection threshold */
116+
int count; /* count of allocations or collections of younger
117+
generations */
118+
};
119+
120+
/* Running stats per generation */
121+
struct gc_generation_stats {
122+
/* total number of collections */
123+
Py_ssize_t collections;
124+
/* total number of collected objects */
125+
Py_ssize_t collected;
126+
/* total number of uncollectable objects (put into gc.garbage) */
127+
Py_ssize_t uncollectable;
128+
};
129+
130+
struct _gc_runtime_state {
131+
/* List of objects that still need to be cleaned up, singly linked
132+
* via their gc headers' gc_prev pointers. */
133+
PyObject *trash_delete_later;
134+
/* Current call-stack depth of tp_dealloc calls. */
135+
int trash_delete_nesting;
136+
137+
int enabled;
138+
int debug;
139+
/* linked lists of container objects */
140+
struct gc_generation generations[NUM_GENERATIONS];
141+
PyGC_Head *generation0;
142+
/* a permanent generation which won't be collected */
143+
struct gc_generation permanent_generation;
144+
struct gc_generation_stats generation_stats[NUM_GENERATIONS];
145+
/* true if we are currently running the collector */
146+
int collecting;
147+
/* list of uncollectable objects */
148+
PyObject *garbage;
149+
/* a list of callbacks to be invoked when collection is performed */
150+
PyObject *callbacks;
151+
/* This is the number of objects that survived the last full
152+
collection. It approximates the number of long lived objects
153+
tracked by the GC.
154+
155+
(by "full collection", we mean a collection of the oldest
156+
generation). */
157+
Py_ssize_t long_lived_total;
158+
/* This is the number of objects that survived all "non-full"
159+
collections, and are awaiting to undergo a full collection for
160+
the first time. */
161+
Py_ssize_t long_lived_pending;
162+
};
163+
164+
PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);
165+
66166
#ifdef __cplusplus
67167
}
68168
#endif

Include/internal/pycore_interp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extern "C" {
1010

1111
#include "pycore_atomic.h" /* _Py_atomic_address */
1212
#include "pycore_gil.h" /* struct _gil_runtime_state */
13-
#include "pycore_pymem.h" /* struct _gc_runtime_state */
13+
#include "pycore_gc.h" /* struct _gc_runtime_state */
1414
#include "pycore_warnings.h" /* struct _warnings_runtime_state */
1515

1616
/* ceval state */

Include/internal/pycore_pymem.h

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -9,107 +9,6 @@ extern "C" {
99
#endif
1010

1111
#include "pymem.h" // PyMemAllocatorName
12-
#include "pycore_gc.h" // PyGC_Head
13-
14-
15-
/* GC runtime state */
16-
17-
/* If we change this, we need to change the default value in the
18-
signature of gc.collect. */
19-
#define NUM_GENERATIONS 3
20-
/*
21-
NOTE: about untracking of mutable objects.
22-
23-
Certain types of container cannot participate in a reference cycle, and
24-
so do not need to be tracked by the garbage collector. Untracking these
25-
objects reduces the cost of garbage collections. However, determining
26-
which objects may be untracked is not free, and the costs must be
27-
weighed against the benefits for garbage collection.
28-
29-
There are two possible strategies for when to untrack a container:
30-
31-
i) When the container is created.
32-
ii) When the container is examined by the garbage collector.
33-
34-
Tuples containing only immutable objects (integers, strings etc, and
35-
recursively, tuples of immutable objects) do not need to be tracked.
36-
The interpreter creates a large number of tuples, many of which will
37-
not survive until garbage collection. It is therefore not worthwhile
38-
to untrack eligible tuples at creation time.
39-
40-
Instead, all tuples except the empty tuple are tracked when created.
41-
During garbage collection it is determined whether any surviving tuples
42-
can be untracked. A tuple can be untracked if all of its contents are
43-
already not tracked. Tuples are examined for untracking in all garbage
44-
collection cycles. It may take more than one cycle to untrack a tuple.
45-
46-
Dictionaries containing only immutable objects also do not need to be
47-
tracked. Dictionaries are untracked when created. If a tracked item is
48-
inserted into a dictionary (either as a key or value), the dictionary
49-
becomes tracked. During a full garbage collection (all generations),
50-
the collector will untrack any dictionaries whose contents are not
51-
tracked.
52-
53-
The module provides the python function is_tracked(obj), which returns
54-
the CURRENT tracking status of the object. Subsequent garbage
55-
collections may change the tracking status of the object.
56-
57-
Untracking of certain containers was introduced in issue #4688, and
58-
the algorithm was refined in response to issue #14775.
59-
*/
60-
61-
struct gc_generation {
62-
PyGC_Head head;
63-
int threshold; /* collection threshold */
64-
int count; /* count of allocations or collections of younger
65-
generations */
66-
};
67-
68-
/* Running stats per generation */
69-
struct gc_generation_stats {
70-
/* total number of collections */
71-
Py_ssize_t collections;
72-
/* total number of collected objects */
73-
Py_ssize_t collected;
74-
/* total number of uncollectable objects (put into gc.garbage) */
75-
Py_ssize_t uncollectable;
76-
};
77-
78-
struct _gc_runtime_state {
79-
/* List of objects that still need to be cleaned up, singly linked
80-
* via their gc headers' gc_prev pointers. */
81-
PyObject *trash_delete_later;
82-
/* Current call-stack depth of tp_dealloc calls. */
83-
int trash_delete_nesting;
84-
85-
int enabled;
86-
int debug;
87-
/* linked lists of container objects */
88-
struct gc_generation generations[NUM_GENERATIONS];
89-
PyGC_Head *generation0;
90-
/* a permanent generation which won't be collected */
91-
struct gc_generation permanent_generation;
92-
struct gc_generation_stats generation_stats[NUM_GENERATIONS];
93-
/* true if we are currently running the collector */
94-
int collecting;
95-
/* list of uncollectable objects */
96-
PyObject *garbage;
97-
/* a list of callbacks to be invoked when collection is performed */
98-
PyObject *callbacks;
99-
/* This is the number of objects that survived the last full
100-
collection. It approximates the number of long lived objects
101-
tracked by the GC.
102-
103-
(by "full collection", we mean a collection of the oldest
104-
generation). */
105-
Py_ssize_t long_lived_total;
106-
/* This is the number of objects that survived all "non-full"
107-
collections, and are awaiting to undergo a full collection for
108-
the first time. */
109-
Py_ssize_t long_lived_pending;
110-
};
111-
112-
PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);
11312

11413

11514
/* Set the memory allocator of the specified domain to the default.

Modules/_tracemalloc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "Python.h"
2-
#include "pycore_pymem.h"
2+
#include "pycore_gc.h" // PyGC_Head
3+
#include "pycore_pymem.h" // _Py_tracemalloc_config
34
#include "pycore_traceback.h"
45
#include "hashtable.h"
56
#include "frameobject.h"

Objects/object.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "pycore_object.h"
99
#include "pycore_pyerrors.h"
1010
#include "pycore_pylifecycle.h"
11+
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
1112
#include "pycore_pystate.h" // _PyThreadState_GET()
1213
#include "frameobject.h"
1314
#include "interpreteridobject.h"

Python/ceval.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@
1010
#define PY_LOCAL_AGGRESSIVE
1111

1212
#include "Python.h"
13-
#include "pycore_abstract.h" // _PyIndex_Check()
13+
#include "pycore_abstract.h" // _PyIndex_Check()
1414
#include "pycore_call.h"
1515
#include "pycore_ceval.h"
1616
#include "pycore_code.h"
1717
#include "pycore_initconfig.h"
1818
#include "pycore_object.h"
1919
#include "pycore_pyerrors.h"
2020
#include "pycore_pylifecycle.h"
21-
#include "pycore_pystate.h" // _PyInterpreterState_GET()
21+
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
22+
#include "pycore_pystate.h" // _PyInterpreterState_GET()
2223
#include "pycore_sysmodule.h"
2324
#include "pycore_tupleobject.h"
2425

0 commit comments

Comments
 (0)