It is not guaranteed to exist in all implementations of Python.
+.. function:: getobjects(limit[, type])
+
+ This function only exists if CPython was built using the
+ specialized configure option :option:`--with-trace-refs`.
+ It is intended only for debugging garbage-collection issues.
+
+ Return a list of up to *limit* dynamically allocated Python objects.
+ If *type* is given, only objects of that exact type (not subtypes)
+ are included.
+
+ Objects from the list are not safe to use.
+ Specifically, the result will include objects from all interpreters that
+ share their object allocator state (that is, ones created with
+ :c:member:`PyInterpreterConfig.use_main_obmalloc` set to 1
+ or using :c:func:`Py_NewInterpreter`, and the
+ :ref:`main interpreter <sub-interpreter-support>`).
+ Mixing objects from different interpreters may lead to crashes
+ or other unexpected behavior.
+
+ .. impl-detail::
+
+ This function should be used for specialized purposes only.
+ It is not guaranteed to exist in all implementations of Python.
+
+ .. versionchanged:: next
+
+ The result may include objects from other interpreters.
+
+
.. function:: getprofile()
.. index::
#define REFCHAIN(interp) interp->object_state.refchain
#define REFCHAIN_VALUE ((void*)(uintptr_t)1)
+static inline int
+has_own_refchain(PyInterpreterState *interp)
+{
+ if (interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC) {
+ return (_Py_IsMainInterpreter(interp)
+ || _PyInterpreterState_Main() == NULL);
+ }
+ return 1;
+}
+
+static int
+refchain_init(PyInterpreterState *interp)
+{
+ if (!has_own_refchain(interp)) {
+ // Legacy subinterpreters share a refchain with the main interpreter.
+ REFCHAIN(interp) = REFCHAIN(_PyInterpreterState_Main());
+ return 0;
+ }
+ _Py_hashtable_allocator_t alloc = {
+ // Don't use default PyMem_Malloc() and PyMem_Free() which
+ // require the caller to hold the GIL.
+ .malloc = PyMem_RawMalloc,
+ .free = PyMem_RawFree,
+ };
+ REFCHAIN(interp) = _Py_hashtable_new_full(
+ _Py_hashtable_hash_ptr, _Py_hashtable_compare_direct,
+ NULL, NULL, &alloc);
+ if (REFCHAIN(interp) == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static void
+refchain_fini(PyInterpreterState *interp)
+{
+ if (has_own_refchain(interp) && REFCHAIN(interp) != NULL) {
+ _Py_hashtable_destroy(REFCHAIN(interp));
+ }
+ REFCHAIN(interp) = NULL;
+}
+
bool
_PyRefchain_IsTraced(PyInterpreterState *interp, PyObject *obj)
{
_PyObject_InitState(PyInterpreterState *interp)
{
#ifdef Py_TRACE_REFS
- _Py_hashtable_allocator_t alloc = {
- // Don't use default PyMem_Malloc() and PyMem_Free() which
- // require the caller to hold the GIL.
- .malloc = PyMem_RawMalloc,
- .free = PyMem_RawFree,
- };
- REFCHAIN(interp) = _Py_hashtable_new_full(
- _Py_hashtable_hash_ptr, _Py_hashtable_compare_direct,
- NULL, NULL, &alloc);
- if (REFCHAIN(interp) == NULL) {
+ if (refchain_init(interp) < 0) {
return _PyStatus_NO_MEMORY();
}
#endif
_PyObject_FiniState(PyInterpreterState *interp)
{
#ifdef Py_TRACE_REFS
- _Py_hashtable_destroy(REFCHAIN(interp));
- REFCHAIN(interp) = NULL;
+ refchain_fini(interp);
#endif
}
#ifdef Py_TRACE_REFS
-/* Make sure the ref is associated with the right interpreter.
- * This only needs special attention for heap-allocated objects
- * that have been immortalized, and only when the object might
- * outlive the interpreter where it was created. That means the
- * object was necessarily created using a global allocator
- * (i.e. from the main interpreter). Thus in that specific case
- * we move the object over to the main interpreter's refchain.
- *
- * This was added for the sake of the immortal interned strings,
- * where legacy subinterpreters share the main interpreter's
- * interned dict (and allocator), and therefore the strings can
- * outlive the subinterpreter.
- *
- * It may make sense to fold this into _Py_SetImmortalUntracked(),
- * but that requires further investigation. In the meantime, it is
- * up to the caller to know if this is needed. There should be
- * very few cases.
- */
-void
-_Py_NormalizeImmortalReference(PyObject *op)
-{
- assert(_Py_IsImmortal(op));
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (!_PyRefchain_IsTraced(interp, op)) {
- return;
- }
- PyInterpreterState *main_interp = _PyInterpreterState_Main();
- if (interp != main_interp
- && interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC)
- {
- assert(!_PyRefchain_IsTraced(main_interp, op));
- _PyRefchain_Remove(interp, op);
- _PyRefchain_Trace(main_interp, op);
- }
-}
-
void
_Py_ForgetReference(PyObject *op)
{
return status;
}
+ // This could be done in init_interpreter() (in pystate.c) if it
+ // didn't depend on interp->feature_flags being set already.
+ status = _PyObject_InitState(interp);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
// initialize the interp->obmalloc state. This must be done after
// the settings are loaded (so that feature_flags are set) but before
// any calls are made to obmalloc functions.
goto error;
}
+ // This could be done in init_interpreter() (in pystate.c) if it
+ // didn't depend on interp->feature_flags being set already.
+ status = _PyObject_InitState(interp);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
// initialize the interp->obmalloc state. This must be done after
// the settings are loaded (so that feature_flags are set) but before
// any calls are made to obmalloc functions.