mirror of
https://github.com/python/cpython.git
synced 2025-07-07 11:25:30 +00:00

* Add "cyclic isolate" to the glossary. * Add a new "Object Life Cycle" page. * Improve docs for related API, with special focus on cross-references and warnings Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
273 lines
13 KiB
ReStructuredText
273 lines
13 KiB
ReStructuredText
.. highlight:: c
|
|
|
|
.. _life-cycle:
|
|
|
|
Object Life Cycle
|
|
=================
|
|
|
|
This section explains how a type's slots relate to each other throughout the
|
|
life of an object. It is not intended to be a complete canonical reference for
|
|
the slots; instead, refer to the slot-specific documentation in
|
|
:ref:`type-structs` for details about a particular slot.
|
|
|
|
|
|
Life Events
|
|
-----------
|
|
|
|
The figure below illustrates the order of events that can occur throughout an
|
|
object's life. An arrow from *A* to *B* indicates that event *B* can occur
|
|
after event *A* has occurred, with the arrow's label indicating the condition
|
|
that must be true for *B* to occur after *A*.
|
|
|
|
.. only:: html and not epub
|
|
|
|
.. raw:: html
|
|
|
|
<style type="text/css">
|
|
|
|
.. raw:: html
|
|
:file: lifecycle.dot.css
|
|
|
|
.. raw:: html
|
|
|
|
</style>
|
|
|
|
.. raw:: html
|
|
:file: lifecycle.dot.svg
|
|
|
|
.. raw:: html
|
|
|
|
<script>
|
|
(() => {
|
|
const g = document.getElementById('life_events_graph');
|
|
const title = g.querySelector(':scope > title');
|
|
title.id = 'life-events-graph-title';
|
|
const svg = g.closest('svg');
|
|
svg.role = 'img';
|
|
svg.setAttribute('aria-describedby',
|
|
'life-events-graph-description');
|
|
svg.setAttribute('aria-labelledby', 'life-events-graph-title');
|
|
})();
|
|
</script>
|
|
|
|
.. only:: epub or not (html or latex)
|
|
|
|
.. image:: lifecycle.dot.svg
|
|
:align: center
|
|
:class: invert-in-dark-mode
|
|
:alt: Diagram showing events in an object's life. Explained in detail
|
|
below.
|
|
|
|
.. only:: latex
|
|
|
|
.. image:: lifecycle.dot.pdf
|
|
:align: center
|
|
:class: invert-in-dark-mode
|
|
:alt: Diagram showing events in an object's life. Explained in detail
|
|
below.
|
|
|
|
.. container::
|
|
:name: life-events-graph-description
|
|
|
|
Explanation:
|
|
|
|
* When a new object is constructed by calling its type:
|
|
|
|
#. :c:member:`~PyTypeObject.tp_new` is called to create a new object.
|
|
#. :c:member:`~PyTypeObject.tp_alloc` is directly called by
|
|
:c:member:`~PyTypeObject.tp_new` to allocate the memory for the new
|
|
object.
|
|
#. :c:member:`~PyTypeObject.tp_init` initializes the newly created object.
|
|
:c:member:`!tp_init` can be called again to re-initialize an object, if
|
|
desired. The :c:member:`!tp_init` call can also be skipped entirely,
|
|
for example by Python code calling :py:meth:`~object.__new__`.
|
|
|
|
* After :c:member:`!tp_init` completes, the object is ready to use.
|
|
* Some time after the last reference to an object is removed:
|
|
|
|
#. If an object is not marked as *finalized*, it might be finalized by
|
|
marking it as *finalized* and calling its
|
|
:c:member:`~PyTypeObject.tp_finalize` function. Python does
|
|
*not* finalize an object when the last reference to it is deleted; use
|
|
:c:func:`PyObject_CallFinalizerFromDealloc` to ensure that
|
|
:c:member:`~PyTypeObject.tp_finalize` is always called.
|
|
#. If the object is marked as finalized,
|
|
:c:member:`~PyTypeObject.tp_clear` might be called by the garbage collector
|
|
to clear references held by the object. It is *not* called when the
|
|
object's reference count reaches zero.
|
|
#. :c:member:`~PyTypeObject.tp_dealloc` is called to destroy the object.
|
|
To avoid code duplication, :c:member:`~PyTypeObject.tp_dealloc` typically
|
|
calls into :c:member:`~PyTypeObject.tp_clear` to free up the object's
|
|
references.
|
|
#. When :c:member:`~PyTypeObject.tp_dealloc` finishes object destruction,
|
|
it directly calls :c:member:`~PyTypeObject.tp_free` (usually set to
|
|
:c:func:`PyObject_Free` or :c:func:`PyObject_GC_Del` automatically as
|
|
appropriate for the type) to deallocate the memory.
|
|
|
|
* The :c:member:`~PyTypeObject.tp_finalize` function is permitted to add a
|
|
reference to the object if desired. If it does, the object is
|
|
*resurrected*, preventing its pending destruction. (Only
|
|
:c:member:`!tp_finalize` is allowed to resurrect an object;
|
|
:c:member:`~PyTypeObject.tp_clear` and
|
|
:c:member:`~PyTypeObject.tp_dealloc` cannot without calling into
|
|
:c:member:`!tp_finalize`.) Resurrecting an object may
|
|
or may not cause the object's *finalized* mark to be removed. Currently,
|
|
Python does not remove the *finalized* mark from a resurrected object if
|
|
it supports garbage collection (i.e., the :c:macro:`Py_TPFLAGS_HAVE_GC`
|
|
flag is set) but does remove the mark if the object does not support
|
|
garbage collection; either or both of these behaviors may change in the
|
|
future.
|
|
* :c:member:`~PyTypeObject.tp_dealloc` can optionally call
|
|
:c:member:`~PyTypeObject.tp_finalize` via
|
|
:c:func:`PyObject_CallFinalizerFromDealloc` if it wishes to reuse that
|
|
code to help with object destruction. This is recommended because it
|
|
guarantees that :c:member:`!tp_finalize` is always called before
|
|
destruction. See the :c:member:`~PyTypeObject.tp_dealloc` documentation
|
|
for example code.
|
|
* If the object is a member of a :term:`cyclic isolate` and either
|
|
:c:member:`~PyTypeObject.tp_clear` fails to break the reference cycle or
|
|
the cyclic isolate is not detected (perhaps :func:`gc.disable` was called,
|
|
or the :c:macro:`Py_TPFLAGS_HAVE_GC` flag was erroneously omitted in one
|
|
of the involved types), the objects remain indefinitely uncollectable
|
|
(they "leak"). See :data:`gc.garbage`.
|
|
|
|
If the object is marked as supporting garbage collection (the
|
|
:c:macro:`Py_TPFLAGS_HAVE_GC` flag is set in
|
|
:c:member:`~PyTypeObject.tp_flags`), the following events are also possible:
|
|
|
|
* The garbage collector occasionally calls
|
|
:c:member:`~PyTypeObject.tp_traverse` to identify :term:`cyclic isolates
|
|
<cyclic isolate>`.
|
|
* When the garbage collector discovers a :term:`cyclic isolate`, it
|
|
finalizes one of the objects in the group by marking it as *finalized* and
|
|
calling its :c:member:`~PyTypeObject.tp_finalize` function, if it has one.
|
|
This repeats until the cyclic isolate doesn't exist or all of the objects
|
|
have been finalized.
|
|
* :c:member:`~PyTypeObject.tp_finalize` is permitted to resurrect the object
|
|
by adding a reference from outside the :term:`cyclic isolate`. The new
|
|
reference causes the group of objects to no longer form a cyclic isolate
|
|
(the reference cycle may still exist, but if it does the objects are no
|
|
longer isolated).
|
|
* When the garbage collector discovers a :term:`cyclic isolate` and all of
|
|
the objects in the group have already been marked as *finalized*, the
|
|
garbage collector clears one or more of the uncleared objects in the group
|
|
(possibly concurrently) by calling each's
|
|
:c:member:`~PyTypeObject.tp_clear` function. This repeats as long as the
|
|
cyclic isolate still exists and not all of the objects have been cleared.
|
|
|
|
|
|
Cyclic Isolate Destruction
|
|
--------------------------
|
|
|
|
Listed below are the stages of life of a hypothetical :term:`cyclic isolate`
|
|
that continues to exist after each member object is finalized or cleared. It
|
|
is a memory leak if a cyclic isolate progresses through all of these stages; it should
|
|
vanish once all objects are cleared, if not sooner. A cyclic isolate can
|
|
vanish either because the reference cycle is broken or because the objects are
|
|
no longer isolated due to finalizer resurrection (see
|
|
:c:member:`~PyTypeObject.tp_finalize`).
|
|
|
|
0. **Reachable** (not yet a cyclic isolate): All objects are in their normal,
|
|
reachable state. A reference cycle could exist, but an external reference
|
|
means the objects are not yet isolated.
|
|
#. **Unreachable but consistent:** The final reference from outside the cyclic
|
|
group of objects has been removed, causing the objects to become isolated
|
|
(thus a cyclic isolate is born). None of the group's objects have been
|
|
finalized or cleared yet. The cyclic isolate remains at this stage until
|
|
some future run of the garbage collector (not necessarily the next run
|
|
because the next run might not scan every object).
|
|
#. **Mix of finalized and not finalized:** Objects in a cyclic isolate are
|
|
finalized one at a time, which means that there is a period of time when the
|
|
cyclic isolate is composed of a mix of finalized and non-finalized objects.
|
|
Finalization order is unspecified, so it can appear random. A finalized
|
|
object must behave in a sane manner when non-finalized objects interact with
|
|
it, and a non-finalized object must be able to tolerate the finalization of
|
|
an arbitrary subset of its referents.
|
|
#. **All finalized:** All objects in a cyclic isolate are finalized before any
|
|
of them are cleared.
|
|
#. **Mix of finalized and cleared:** The objects can be cleared serially or
|
|
concurrently (but with the :term:`GIL` held); either way, some will finish
|
|
before others. A finalized object must be able to tolerate the clearing of
|
|
a subset of its referents. :pep:`442` calls this stage "cyclic trash".
|
|
#. **Leaked:** If a cyclic isolate still exists after all objects in the group
|
|
have been finalized and cleared, then the objects remain indefinitely
|
|
uncollectable (see :data:`gc.garbage`). It is a bug if a cyclic isolate
|
|
reaches this stage---it means the :c:member:`~PyTypeObject.tp_clear` methods
|
|
of the participating objects have failed to break the reference cycle as
|
|
required.
|
|
|
|
If :c:member:`~PyTypeObject.tp_clear` did not exist, then Python would have no
|
|
way to safely break a reference cycle. Simply destroying an object in a cyclic
|
|
isolate would result in a dangling pointer, triggering undefined behavior when
|
|
an object referencing the destroyed object is itself destroyed. The clearing
|
|
step makes object destruction a two-phase process: first
|
|
:c:member:`~PyTypeObject.tp_clear` is called to partially destroy the objects
|
|
enough to detangle them from each other, then
|
|
:c:member:`~PyTypeObject.tp_dealloc` is called to complete the destruction.
|
|
|
|
Unlike clearing, finalization is not a phase of destruction. A finalized
|
|
object must still behave properly by continuing to fulfill its design
|
|
contracts. An object's finalizer is allowed to execute arbitrary Python code,
|
|
and is even allowed to prevent the impending destruction by adding a reference.
|
|
The finalizer is only related to destruction by call order---if it runs, it runs
|
|
before destruction, which starts with :c:member:`~PyTypeObject.tp_clear` (if
|
|
called) and concludes with :c:member:`~PyTypeObject.tp_dealloc`.
|
|
|
|
The finalization step is not necessary to safely reclaim the objects in a
|
|
cyclic isolate, but its existence makes it easier to design types that behave
|
|
in a sane manner when objects are cleared. Clearing an object might
|
|
necessarily leave it in a broken, partially destroyed state---it might be
|
|
unsafe to call any of the cleared object's methods or access any of its
|
|
attributes. With finalization, only finalized objects can possibly interact
|
|
with cleared objects; non-finalized objects are guaranteed to interact with
|
|
only non-cleared (but potentially finalized) objects.
|
|
|
|
To summarize the possible interactions:
|
|
|
|
* A non-finalized object might have references to or from non-finalized and
|
|
finalized objects, but not to or from cleared objects.
|
|
* A finalized object might have references to or from non-finalized, finalized,
|
|
and cleared objects.
|
|
* A cleared object might have references to or from finalized and cleared
|
|
objects, but not to or from non-finalized objects.
|
|
|
|
Without any reference cycles, an object can be simply destroyed once its last
|
|
reference is deleted; the finalization and clearing steps are not necessary to
|
|
safely reclaim unused objects. However, it can be useful to automatically call
|
|
:c:member:`~PyTypeObject.tp_finalize` and :c:member:`~PyTypeObject.tp_clear`
|
|
before destruction anyway because type design is simplified when all objects
|
|
always experience the same series of events regardless of whether they
|
|
participated in a cyclic isolate. Python currently only calls
|
|
:c:member:`~PyTypeObject.tp_finalize` and :c:member:`~PyTypeObject.tp_clear` as
|
|
needed to destroy a cyclic isolate; this may change in a future version.
|
|
|
|
|
|
Functions
|
|
---------
|
|
|
|
To allocate and free memory, see :ref:`allocating-objects`.
|
|
|
|
|
|
.. c:function:: void PyObject_CallFinalizer(PyObject *op)
|
|
|
|
Finalizes the object as described in :c:member:`~PyTypeObject.tp_finalize`.
|
|
Call this function (or :c:func:`PyObject_CallFinalizerFromDealloc`) instead
|
|
of calling :c:member:`~PyTypeObject.tp_finalize` directly because this
|
|
function may deduplicate multiple calls to :c:member:`!tp_finalize`.
|
|
Currently, calls are only deduplicated if the type supports garbage
|
|
collection (i.e., the :c:macro:`Py_TPFLAGS_HAVE_GC` flag is set); this may
|
|
change in the future.
|
|
|
|
|
|
.. c:function:: int PyObject_CallFinalizerFromDealloc(PyObject *op)
|
|
|
|
Same as :c:func:`PyObject_CallFinalizer` but meant to be called at the
|
|
beginning of the object's destructor (:c:member:`~PyTypeObject.tp_dealloc`).
|
|
There must not be any references to the object. If the object's finalizer
|
|
resurrects the object, this function returns -1; no further destruction
|
|
should happen. Otherwise, this function returns 0 and destruction can
|
|
continue normally.
|
|
|
|
.. seealso::
|
|
|
|
:c:member:`~PyTypeObject.tp_dealloc` for example code.
|