[3.14] gh-149242: Heap size should be added at end of the struct by DinoV · Pull Request #149241 · python/cpython
Not modifying the offsets of existing members seems prudent, can't really hurt. However, I think since we have changed other members of the struct, we need to have a different patch, the recent changes to this struct are as follows:
struct _gc_runtime_state {
/* List of objects that still need to be cleaned up, singly linked
* via their gc headers' gc_prev pointers. */
PyObject *trash_delete_later;
/* Current call-stack depth of tp_dealloc calls. */
int trash_delete_nesting;
/* Is automatic collection enabled? */
int enabled;
int debug;
/* linked lists of container objects */
+#ifndef Py_GIL_DISABLED
+ struct gc_generation generations[NUM_GENERATIONS];
+ PyGC_Head *generation0;
+#else
struct gc_generation young;
struct gc_generation old[2];
+#endif
/* a permanent generation which won't be collected */
struct gc_generation permanent_generation;
struct gc_generation_stats generation_stats[NUM_GENERATIONS];
/* true if we are currently running the collector */
int collecting;
/* list of uncollectable objects */
PyObject *garbage;
/* a list of callbacks to be invoked when collection is performed */
PyObject *callbacks;
+ /* The number of live objects. */
Py_ssize_t heap_size;
- Py_ssize_t work_to_do;
- /* Which of the old spaces is the visited space */
- int visited_space;
- int phase;
-#ifdef Py_GIL_DISABLED
/* This is the number of objects that survived the last full
collection. It approximates the number of long lived objects
tracked by the GC.
(by "full collection", we mean a collection of the oldest
generation). */
Py_ssize_t long_lived_total;
/* This is the number of objects that survived all "non-full"
collections, and are awaiting to undergo a full collection for
the first time. */
Py_ssize_t long_lived_pending;
+#ifdef Py_GIL_DISABLED
/* True if gc.freeze() has been used. */
int freeze_active;
/* Memory usage of the process (RSS + swap) after last GC. */
Py_ssize_t last_mem;
/* This accumulates the new object count whenever collection is deferred
due to the RSS increase condition not being meet. Reset on collection. */
Py_ssize_t deferred_count;
/* Mutex held for gc_should_collect_mem_usage(). */
PyMutex mutex;
#endif
};I would think we want something like the following, to preserve as many offsets as we can:
--- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -210,13 +210,10 @@ struct _gc_runtime_state { int enabled; int debug; /* linked lists of container objects */ -#ifndef Py_GIL_DISABLED - struct gc_generation generations[NUM_GENERATIONS]; - PyGC_Head *generation0; -#else + /* Note this is only used for the Py_GIL_DISABLED build, retained to preserve + * other member offsets. */ struct gc_generation young; struct gc_generation old[2]; -#endif /* a permanent generation which won't be collected */ struct gc_generation permanent_generation; struct gc_generation_stats generation_stats[NUM_GENERATIONS]; @@ -230,6 +227,11 @@ struct _gc_runtime_state { /* The number of live objects. */ Py_ssize_t heap_size; + /* dummy members to preserve other offsets */ + Py_ssize_t dummy1; /* was work_to_do */ + int dummy2; /* was visited_space */ + int dummy3; /* was phase */ + /* This is the number of objects that survived the last full collection. It approximates the number of long lived objects tracked by the GC. @@ -255,6 +257,10 @@ struct _gc_runtime_state { /* Mutex held for gc_should_collect_mem_usage(). */ PyMutex mutex; +#else + /* linked lists of container objects */ + struct gc_generation generations[NUM_GENERATIONS]; + PyGC_Head *generation0; #endif };