Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5187f31

Browse files
committed
gh-75459: Doc: C API: Improve object life cycle documentation
* Add "cyclic isolate" to the glossary. * Add a new "Object Life Cycle" page. * Illustrate the order of life cycle functions. * Document `PyObject_CallFinalizer` and `PyObject_CallFinalizerFromDealloc`. * `PyObject_Init` does not call `tp_init`. * `PyObject_New`: * also initializes the memory * does not call `tp_alloc`, `tp_new`, or `tp_init` * should not be used for GC-enabled objects * memory must be freed by `PyObject_Free` * `PyObject_GC_New` memory must be freed by `PyObject_GC_Del`. * Warn that garbage collector functions can be called from any thread. * `tp_finalize` and `tp_clear`: * Only called when there's a cyclic isolate. * Only one object in the cyclic isolate is finalized/cleared at a time. * Clearly warn that they might not be called. * They can optionally be manually called from `tp_dealloc` (via `PyObject_CallFinalizerFromDealloc` in the case of `tp_finalize`). * `tp_finalize`: * Reference `object.__del__`. * The finalizer can resurrect the object. * Suggest `PyErr_GetRaisedException` and `PyErr_SetRaisedException` instead of the deprecated `PyErr_Fetch` and `PyErr_Restore` functions. * Add links to `PyErr_GetRaisedException` and `PyErr_SetRaisedException`. * Suggest using `PyErr_WriteUnraisable` if an exception is raised during finalization. * Rename the example function from `local_finalize` to `foo_finalize` for consistency with the `tp_dealloc` documentation and as a hint that the name isn't special. * Minor wording and sylistic tweaks. * Warn that `tp_finalize` can be called during shutdown.
1 parent 75401fe commit 5187f31

File tree

7 files changed

+358
-44
lines changed

7 files changed

+358
-44
lines changed

Doc/c-api/allocation.rst

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ Allocating Objects on the Heap
1818
reference. Returns the initialized object. If *type* indicates that the
1919
object participates in the cyclic garbage detector, it is added to the
2020
detector's set of observed objects. Other fields of the object are not
21-
affected.
21+
initialized. Specifically, this function does **not** call the object's
22+
:meth:`~object.__init__` method (:c:member:`~PyTypeObject.tp_init` slot).
2223
2324
2425
.. c:function:: PyVarObject* PyObject_InitVar(PyVarObject *op, PyTypeObject *type, Py_ssize_t size)
@@ -29,27 +30,44 @@ Allocating Objects on the Heap
2930
3031
.. c:macro:: PyObject_New(TYPE, typeobj)
3132
32-
Allocate a new Python object using the C structure type *TYPE*
33-
and the Python type object *typeobj* (``PyTypeObject*``).
34-
Fields not defined by the Python object header are not initialized.
35-
The caller will own the only reference to the object
36-
(i.e. its reference count will be one).
37-
The size of the memory allocation is determined from the
38-
:c:member:`~PyTypeObject.tp_basicsize` field of the type object.
33+
Calls :c:func:`PyObject_Malloc` to allocate memory for a new Python object
34+
using the C structure type *TYPE* and the Python type object *typeobj*
35+
(``PyTypeObject*``), then initializes the memory like
36+
:c:func:`PyObject_Init`. The caller will own the only reference to the
37+
object (i.e. its reference count will be one). The size of the memory
38+
allocation is determined from the :c:member:`~PyTypeObject.tp_basicsize`
39+
field of the type object.
40+
41+
This does not call :c:member:`~PyTypeObject.tp_alloc`,
42+
:c:member:`~PyTypeObject.tp_new` (:meth:`~object.__new__`), or
43+
:c:member:`~PyTypeObject.tp_init` (:meth:`~object.__init__`).
44+
45+
This should not be used for objects with :c:macro:`Py_TPFLAGS_HAVE_GC` set
46+
in :c:member:`~PyTypeObject.tp_flags`; use :c:macro:`PyObject_GC_New`
47+
instead.
48+
49+
Memory allocated by this function must be freed with :c:func:`PyObject_Free`.
3950
4051
4152
.. c:macro:: PyObject_NewVar(TYPE, typeobj, size)
4253
43-
Allocate a new Python object using the C structure type *TYPE* and the
44-
Python type object *typeobj* (``PyTypeObject*``).
45-
Fields not defined by the Python object header
46-
are not initialized. The allocated memory allows for the *TYPE* structure
47-
plus *size* (``Py_ssize_t``) fields of the size
48-
given by the :c:member:`~PyTypeObject.tp_itemsize` field of
49-
*typeobj*. This is useful for implementing objects like tuples, which are
50-
able to determine their size at construction time. Embedding the array of
51-
fields into the same allocation decreases the number of allocations,
52-
improving the memory management efficiency.
54+
Like :c:macro:`PyObject_New` except:
55+
56+
* It allocates enough memory for the *TYPE* structure plus *size*
57+
(``Py_ssize_t``) fields of the size given by the
58+
:c:member:`~PyTypeObject.tp_itemsize` field of *typeobj*.
59+
* The memory is initialized like :c:func:`PyObject_InitVar`.
60+
61+
This is useful for implementing objects like tuples, which are able to
62+
determine their size at construction time. Embedding the array of fields
63+
into the same allocation decreases the number of allocations, improving the
64+
memory management efficiency.
65+
66+
This should not be used for objects with :c:macro:`Py_TPFLAGS_HAVE_GC` set
67+
in :c:member:`~PyTypeObject.tp_flags`; use :c:macro:`PyObject_GC_NewVar`
68+
instead.
69+
70+
Memory allocated by this function must be freed with :c:func:`PyObject_Free`.
5371
5472
5573
.. c:function:: void PyObject_Del(void *op)

Doc/c-api/gcsupport.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,17 @@ rules:
5757
Analogous to :c:macro:`PyObject_New` but for container objects with the
5858
:c:macro:`Py_TPFLAGS_HAVE_GC` flag set.
5959

60+
Memory allocated by this function must be freed with
61+
:c:func:`PyObject_GC_Del`.
62+
6063
.. c:macro:: PyObject_GC_NewVar(TYPE, typeobj, size)
6164
6265
Analogous to :c:macro:`PyObject_NewVar` but for container objects with the
6366
:c:macro:`Py_TPFLAGS_HAVE_GC` flag set.
6467

68+
Memory allocated by this function must be freed with
69+
:c:func:`PyObject_GC_Del`.
70+
6571
.. c:function:: PyObject* PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size)
6672
6773
Analogous to :c:macro:`PyObject_GC_New` but allocates *extra_size*
@@ -73,6 +79,9 @@ rules:
7379
The extra data will be deallocated with the object, but otherwise it is
7480
not managed by Python.
7581
82+
Memory allocated by this function must be freed with
83+
:c:func:`PyObject_GC_Del`.
84+
7685
.. warning::
7786
The function is marked as unstable because the final mechanism
7887
for reserving extra data after an instance is not yet decided.

Doc/c-api/lifecycle.rst

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
.. highlight:: c
2+
3+
.. _life-cycle:
4+
5+
Object Life Cycle
6+
=================
7+
8+
Stages
9+
------
10+
11+
The following is an illustration of the stages of life of an object. Arrows
12+
indicate a "happens before" relationship. Octagons indicate functions specific
13+
to :ref:`garbage collection support <supporting-cycle-detection>`.
14+
15+
.. digraph:: callorder
16+
17+
graph [
18+
fontname="svg"
19+
fontsize=10.0
20+
layout="dot"
21+
ranksep=0.25
22+
]
23+
node [
24+
fontname="Courier"
25+
fontsize=10.0
26+
]
27+
edge [
28+
fontname="Times-Italic"
29+
fontsize=10.0
30+
]
31+
32+
"start" [fontname="Times-Italic" shape=plain label=< start > style=invis]
33+
"tp_alloc" [href="typeobj.html#c.PyTypeObject.tp_alloc" target="_top"]
34+
"tp_new" [href="typeobj.html#c.PyTypeObject.tp_new" target="_top"]
35+
"tp_init" [href="typeobj.html#c.PyTypeObject.tp_init" target="_top"]
36+
{
37+
rank="same"
38+
"alive" [
39+
fontname="Times-Italic"
40+
label=<alive, ref count &gt; 0>
41+
shape=box
42+
]
43+
"tp_traverse" [
44+
href="typeobj.html#c.PyTypeObject.tp_traverse"
45+
shape=octagon
46+
target="_top"
47+
]
48+
}
49+
"tp_finalize" [
50+
href="typeobj.html#c.PyTypeObject.tp_finalize"
51+
shape=octagon
52+
target="_top"
53+
]
54+
"tp_clear" [
55+
href="typeobj.html#c.PyTypeObject.tp_clear"
56+
shape=octagon
57+
target="_top"
58+
]
59+
"ref0" [
60+
fontname="Times-Italic"
61+
label=<ref count == 0>
62+
ordering="in"
63+
shape=box
64+
]
65+
"tp_dealloc" [href="typeobj.html#c.PyTypeObject.tp_dealloc" target="_top"]
66+
"tp_free" [href="typeobj.html#c.PyTypeObject.tp_free" target="_top"]
67+
68+
"start" -> "tp_alloc"
69+
"tp_alloc" -> "tp_new"
70+
"tp_new" -> "tp_init"
71+
"tp_init" -> "alive"
72+
"tp_traverse" -> "alive"
73+
"alive" -> "tp_traverse"
74+
"alive" -> "tp_clear" [label=< cyclic <br/>isolate >]
75+
"alive" -> "tp_finalize" [
76+
dir="back"
77+
label=< resurrected >
78+
]
79+
"alive" -> "tp_finalize" [label=< cyclic <br/>isolate >]
80+
"tp_finalize" -> "tp_clear"
81+
"tp_finalize" -> "ref0"
82+
"tp_clear" -> "ref0"
83+
"tp_clear" -> "tp_dealloc" [
84+
dir="back"
85+
label=< optional<br/>direct call >
86+
]
87+
"alive" -> "ref0"
88+
"ref0" -> "tp_dealloc"
89+
"tp_finalize" -> "tp_dealloc" [
90+
dir="back"
91+
href="lifecycle.html#c.PyObject_CallFinalizerFromDealloc"
92+
label=<
93+
<table border="0" cellborder="0" cellpadding="0" cellspacing="0">
94+
<tr>
95+
<td rowspan="4"> </td>
96+
<td align="left">optional call to</td>
97+
<td rowspan="4"> </td>
98+
</tr>
99+
<tr>
100+
<td align="left"><font face="Courier">PyObject_Call</font></td>
101+
</tr>
102+
<tr>
103+
<td align="left"><font face="Courier">FinalizerFrom</font></td>
104+
</tr>
105+
<tr><td align="left"><font face="Courier">Dealloc</font></td></tr>
106+
</table>
107+
>
108+
target="_top"
109+
]
110+
"tp_dealloc" -> "tp_free" [label=< directly calls >]
111+
112+
Explanation:
113+
114+
* :c:member:`~PyTypeObject.tp_alloc`, :c:member:`~PyTypeObject.tp_new`, and
115+
:c:member:`~PyTypeObject.tp_init` are called to allocate memory for a new
116+
object and initialize the object.
117+
* If the reference count for an object drops to 0,
118+
:c:member:`~PyTypeObject.tp_dealloc` is called to destroy the object.
119+
* :c:member:`~PyTypeObject.tp_dealloc` can optionally call
120+
:c:member:`~PyTypeObject.tp_finalize` (if non-``NULL``) via
121+
:c:func:`PyObject_CallFinalizerFromDealloc` if it wishes to reuse that code
122+
to help with object destruction.
123+
* :c:member:`~PyTypeObject.tp_finalize` may increase the object's reference
124+
count, halting the destruction. The object is said to be resurrected.
125+
* :c:member:`~PyTypeObject.tp_dealloc` can optionally call
126+
:c:member:`~PyTypeObject.tp_clear` (if non-``NULL``) if it wishes to reuse
127+
that code to help with object destruction.
128+
* When :c:member:`~PyTypeObject.tp_dealloc` finishes object destruction, it
129+
directly calls :c:member:`~PyTypeObject.tp_free` to deallocate the memory.
130+
131+
If the object is marked as supporting garbage collection (the
132+
:c:macro:`Py_TPFLAGS_HAVE_GC` flag is set in
133+
:c:member:`~PyTypeObject.tp_flags`), the following stages are also possible:
134+
135+
* The garbage collector occasionally calls
136+
:c:member:`~PyTypeObject.tp_traverse` to identify :term:`cyclic isolates
137+
<cyclic isolate>`.
138+
* When the garbage collector discovers a cyclic isolate, it finalizes one of
139+
the objects in the group by calling its :c:member:`~PyTypeObject.tp_finalize`
140+
function. This repeats until the cyclic isolate doesn't exist or all of the
141+
objects have been finalized.
142+
* The :c:member:`~PyTypeObject.tp_finalize` function can optionally increase
143+
the object's reference count, causing it (and other objects it references) to
144+
become resurrected and no longer a member of a cyclic isolate.
145+
* When the garbage collector discovers a cyclic isolate and all of the objects
146+
in the group have already been finalized, the garbage collector clears one of
147+
the objects in the group by calling its :c:member:`~PyTypeObject.tp_clear`
148+
function. This repeats until the cyclic isolate doesn't exist or all of the
149+
objects have been cleared.
150+
151+
152+
Functions
153+
---------
154+
155+
To allocate and free memory, see :ref:`Allocating Objects on the Heap
156+
<allocating-objects>`.
157+
158+
159+
.. c:function:: void PyObject_CallFinalizer(PyObject *op)
160+
161+
Calls the object's finalizer (:c:member:`~PyTypeObject.tp_finalize`) if it
162+
has not already been called.
163+
164+
165+
.. c:function:: int PyObject_CallFinalizerFromDealloc(PyObject *op)
166+
167+
Calls the object's finalizer (:c:member:`~PyTypeObject.tp_finalize`) if it
168+
has not already been called. This function is intended to be called at the
169+
beginning of the object's destructor (:c:member:`~PyTypeObject.tp_dealloc`).
170+
The object's reference count must already be 0. If the object's finalizer
171+
increases the object's reference count, the object is resurrected and this
172+
function returns -1; no further destruction should happen. Otherwise, this
173+
function returns 0 and destruction can continue normally.

Doc/c-api/objimpl.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ object types.
1212
.. toctree::
1313

1414
allocation.rst
15+
lifecycle.rst
1516
structures.rst
1617
typeobj.rst
1718
gcsupport.rst

0 commit comments

Comments
 (0)