Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Include/internal/pycore_gc.h
12 views
1
#ifndef Py_INTERNAL_GC_H
2
#define Py_INTERNAL_GC_H
3
#ifdef __cplusplus
4
extern "C" {
5
#endif
6
7
#ifndef Py_BUILD_CORE
8
# error "this header requires Py_BUILD_CORE define"
9
#endif
10
11
/* GC information is stored BEFORE the object structure. */
12
typedef struct {
13
// Pointer to next object in the list.
14
// 0 means the object is not tracked
15
uintptr_t _gc_next;
16
17
// Pointer to previous object in the list.
18
// Lowest two bits are used for flags documented later.
19
uintptr_t _gc_prev;
20
} PyGC_Head;
21
22
#define _PyGC_Head_UNUSED PyGC_Head
23
24
25
/* Get an object's GC head */
26
static inline PyGC_Head* _Py_AS_GC(PyObject *op) {
27
char *gc = ((char*)op) - sizeof(PyGC_Head);
28
return (PyGC_Head*)gc;
29
}
30
31
/* Get the object given the GC head */
32
static inline PyObject* _Py_FROM_GC(PyGC_Head *gc) {
33
char *op = ((char *)gc) + sizeof(PyGC_Head);
34
return (PyObject *)op;
35
}
36
37
38
/* True if the object is currently tracked by the GC. */
39
static inline int _PyObject_GC_IS_TRACKED(PyObject *op) {
40
PyGC_Head *gc = _Py_AS_GC(op);
41
return (gc->_gc_next != 0);
42
}
43
#define _PyObject_GC_IS_TRACKED(op) _PyObject_GC_IS_TRACKED(_Py_CAST(PyObject*, op))
44
45
/* True if the object may be tracked by the GC in the future, or already is.
46
This can be useful to implement some optimizations. */
47
static inline int _PyObject_GC_MAY_BE_TRACKED(PyObject *obj) {
48
if (!PyObject_IS_GC(obj)) {
49
return 0;
50
}
51
if (PyTuple_CheckExact(obj)) {
52
return _PyObject_GC_IS_TRACKED(obj);
53
}
54
return 1;
55
}
56
57
58
/* Bit flags for _gc_prev */
59
/* Bit 0 is set when tp_finalize is called */
60
#define _PyGC_PREV_MASK_FINALIZED (1)
61
/* Bit 1 is set when the object is in generation which is GCed currently. */
62
#define _PyGC_PREV_MASK_COLLECTING (2)
63
/* The (N-2) most significant bits contain the real address. */
64
#define _PyGC_PREV_SHIFT (2)
65
#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
66
67
// Lowest bit of _gc_next is used for flags only in GC.
68
// But it is always 0 for normal code.
69
static inline PyGC_Head* _PyGCHead_NEXT(PyGC_Head *gc) {
70
uintptr_t next = gc->_gc_next;
71
return (PyGC_Head*)next;
72
}
73
static inline void _PyGCHead_SET_NEXT(PyGC_Head *gc, PyGC_Head *next) {
74
gc->_gc_next = (uintptr_t)next;
75
}
76
77
// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
78
static inline PyGC_Head* _PyGCHead_PREV(PyGC_Head *gc) {
79
uintptr_t prev = (gc->_gc_prev & _PyGC_PREV_MASK);
80
return (PyGC_Head*)prev;
81
}
82
static inline void _PyGCHead_SET_PREV(PyGC_Head *gc, PyGC_Head *prev) {
83
uintptr_t uprev = (uintptr_t)prev;
84
assert((uprev & ~_PyGC_PREV_MASK) == 0);
85
gc->_gc_prev = ((gc->_gc_prev & ~_PyGC_PREV_MASK) | uprev);
86
}
87
88
static inline int _PyGCHead_FINALIZED(PyGC_Head *gc) {
89
return ((gc->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0);
90
}
91
static inline void _PyGCHead_SET_FINALIZED(PyGC_Head *gc) {
92
gc->_gc_prev |= _PyGC_PREV_MASK_FINALIZED;
93
}
94
95
static inline int _PyGC_FINALIZED(PyObject *op) {
96
PyGC_Head *gc = _Py_AS_GC(op);
97
return _PyGCHead_FINALIZED(gc);
98
}
99
static inline void _PyGC_SET_FINALIZED(PyObject *op) {
100
PyGC_Head *gc = _Py_AS_GC(op);
101
_PyGCHead_SET_FINALIZED(gc);
102
}
103
104
105
/* GC runtime state */
106
107
/* If we change this, we need to change the default value in the
108
signature of gc.collect. */
109
#define NUM_GENERATIONS 3
110
/*
111
NOTE: about untracking of mutable objects.
112
113
Certain types of container cannot participate in a reference cycle, and
114
so do not need to be tracked by the garbage collector. Untracking these
115
objects reduces the cost of garbage collections. However, determining
116
which objects may be untracked is not free, and the costs must be
117
weighed against the benefits for garbage collection.
118
119
There are two possible strategies for when to untrack a container:
120
121
i) When the container is created.
122
ii) When the container is examined by the garbage collector.
123
124
Tuples containing only immutable objects (integers, strings etc, and
125
recursively, tuples of immutable objects) do not need to be tracked.
126
The interpreter creates a large number of tuples, many of which will
127
not survive until garbage collection. It is therefore not worthwhile
128
to untrack eligible tuples at creation time.
129
130
Instead, all tuples except the empty tuple are tracked when created.
131
During garbage collection it is determined whether any surviving tuples
132
can be untracked. A tuple can be untracked if all of its contents are
133
already not tracked. Tuples are examined for untracking in all garbage
134
collection cycles. It may take more than one cycle to untrack a tuple.
135
136
Dictionaries containing only immutable objects also do not need to be
137
tracked. Dictionaries are untracked when created. If a tracked item is
138
inserted into a dictionary (either as a key or value), the dictionary
139
becomes tracked. During a full garbage collection (all generations),
140
the collector will untrack any dictionaries whose contents are not
141
tracked.
142
143
The module provides the python function is_tracked(obj), which returns
144
the CURRENT tracking status of the object. Subsequent garbage
145
collections may change the tracking status of the object.
146
147
Untracking of certain containers was introduced in issue #4688, and
148
the algorithm was refined in response to issue #14775.
149
*/
150
151
struct gc_generation {
152
PyGC_Head head;
153
int threshold; /* collection threshold */
154
int count; /* count of allocations or collections of younger
155
generations */
156
};
157
158
/* Running stats per generation */
159
struct gc_generation_stats {
160
/* total number of collections */
161
Py_ssize_t collections;
162
/* total number of collected objects */
163
Py_ssize_t collected;
164
/* total number of uncollectable objects (put into gc.garbage) */
165
Py_ssize_t uncollectable;
166
};
167
168
struct _gc_runtime_state {
169
/* List of objects that still need to be cleaned up, singly linked
170
* via their gc headers' gc_prev pointers. */
171
PyObject *trash_delete_later;
172
/* Current call-stack depth of tp_dealloc calls. */
173
int trash_delete_nesting;
174
175
/* Is automatic collection enabled? */
176
int enabled;
177
int debug;
178
/* linked lists of container objects */
179
struct gc_generation generations[NUM_GENERATIONS];
180
PyGC_Head *generation0;
181
/* a permanent generation which won't be collected */
182
struct gc_generation permanent_generation;
183
struct gc_generation_stats generation_stats[NUM_GENERATIONS];
184
/* true if we are currently running the collector */
185
int collecting;
186
/* list of uncollectable objects */
187
PyObject *garbage;
188
/* a list of callbacks to be invoked when collection is performed */
189
PyObject *callbacks;
190
/* This is the number of objects that survived the last full
191
collection. It approximates the number of long lived objects
192
tracked by the GC.
193
194
(by "full collection", we mean a collection of the oldest
195
generation). */
196
Py_ssize_t long_lived_total;
197
/* This is the number of objects that survived all "non-full"
198
collections, and are awaiting to undergo a full collection for
199
the first time. */
200
Py_ssize_t long_lived_pending;
201
};
202
203
204
extern void _PyGC_InitState(struct _gc_runtime_state *);
205
206
extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate);
207
208
209
// Functions to clear types free lists
210
extern void _PyTuple_ClearFreeList(PyInterpreterState *interp);
211
extern void _PyFloat_ClearFreeList(PyInterpreterState *interp);
212
extern void _PyList_ClearFreeList(PyInterpreterState *interp);
213
extern void _PyDict_ClearFreeList(PyInterpreterState *interp);
214
extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp);
215
extern void _PyContext_ClearFreeList(PyInterpreterState *interp);
216
extern void _Py_ScheduleGC(PyInterpreterState *interp);
217
extern void _Py_RunGC(PyThreadState *tstate);
218
219
#ifdef __cplusplus
220
}
221
#endif
222
#endif /* !Py_INTERNAL_GC_H */
223
224