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

Skip to content

Commit 544de1e

Browse files
committed
- Add DEBUG_SAVEALL option. When enabled all garbage objects found by the
collector will be saved in gc.garbage. This is useful for debugging a program that creates reference cycles. - Fix else statements in gcmodule.c to conform to Python coding standards.
1 parent 676940b commit 544de1e

2 files changed

Lines changed: 49 additions & 29 deletions

File tree

Doc/lib/libgc.tex

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ \section{\module{gc} ---
8585
A list of objects which the collector found to be unreachable
8686
but could not be freed (uncollectable objects). Objects that have
8787
\method{__del__()} methods and create part of a reference cycle cause
88-
the entire reference cycle to be uncollectable.
88+
the entire reference cycle to be uncollectable. If
89+
\constant{DEBUG_SAVEALL} is set, then all unreachable objects will
90+
be added to this list rather than freed.
8991
\end{datadesc}
9092

9193

@@ -117,8 +119,14 @@ \section{\module{gc} ---
117119
set, print information about objects other than instance objects found.
118120
\end{datadesc}
119121

122+
\begin{datadesc}{DEBUG_SAVEALL}
123+
When set, all unreachable objects found will be appended to
124+
\var{garbage} rather than being freed. This can be useful for debugging
125+
a leaking program.
126+
\end{datadesc}
127+
120128
\begin{datadesc}{DEBUG_LEAK}
121129
The debugging flags necessary for the collector to print
122130
information about a leaking program (equal to \code{DEBUG_COLLECTABLE |
123-
DEBUG_UNCOLLECTABLE | DEBUG_INSTANCES | DEBUG_OBJECTS}).
131+
DEBUG_UNCOLLECTABLE | DEBUG_INSTANCES | DEBUG_OBJECTS | DEBUG_SAVEALL}).
124132
\end{datadesc}

Modules/gcmodule.c

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ static int allocated;
5353
#define DEBUG_UNCOLLECTABLE (1<<2) /* print uncollectable objects */
5454
#define DEBUG_INSTANCES (1<<3) /* print instances */
5555
#define DEBUG_OBJECTS (1<<4) /* print other objects */
56+
#define DEBUG_SAVEALL (1<<5) /* save all garbage in gc.garbage */
5657
#define DEBUG_LEAK DEBUG_COLLECTABLE | \
5758
DEBUG_UNCOLLECTABLE | \
5859
DEBUG_INSTANCES | \
59-
DEBUG_OBJECTS
60+
DEBUG_OBJECTS | \
61+
DEBUG_SAVEALL
6062
static int debug;
6163

6264
/* list of uncollectable objects */
@@ -100,7 +102,8 @@ gc_list_move(PyGC_Head *from, PyGC_Head *to)
100102
if (from->gc_next == from) {
101103
/* empty from list */
102104
gc_list_init(to);
103-
} else {
105+
}
106+
else {
104107
to->gc_next = from->gc_next;
105108
to->gc_next->gc_prev = to;
106109
to->gc_prev = from->gc_prev;
@@ -290,7 +293,8 @@ debug_cycle(char *msg, PyObject *op)
290293
{
291294
if ((debug & DEBUG_INSTANCES) && PyInstance_Check(op)) {
292295
debug_instance(msg, (PyInstanceObject *)op);
293-
} else if (debug & DEBUG_OBJECTS) {
296+
}
297+
else if (debug & DEBUG_OBJECTS) {
294298
PySys_WriteStderr("gc: %.100s <%.100s %p>\n",
295299
msg, op->ob_type->tp_name, op);
296300
}
@@ -307,19 +311,20 @@ handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
307311
for (gc = finalizers->gc_next; gc != finalizers;
308312
gc = finalizers->gc_next) {
309313
PyObject *op = PyObject_FROM_GC(gc);
310-
/* Add all instances to a Python accessible list of garbage */
311-
if (PyInstance_Check(op)) {
314+
if ((debug & DEBUG_SAVEALL) || PyInstance_Check(op)) {
315+
/* If SAVEALL is not set then just append
316+
* instances to the list of garbage. We assume
317+
* that all objects in the finalizers list are
318+
* reachable from instances. */
312319
PyList_Append(garbage, op);
313320
}
314-
/* We assume that all objects in finalizers are reachable from
315-
* instances. Once we add the instances to the garbage list
316-
* everything is reachable from Python again. */
321+
/* object is now reachable again */
317322
gc_list_remove(gc);
318323
gc_list_append(gc, old);
319324
}
320325
}
321326

322-
/* Break reference cycles by clearing the containers involved. This is
327+
/* Break reference cycles by clearing the containers involved. This is
323328
* tricky business as the lists can be changing and we don't know which
324329
* objects may be freed. It is possible I screwed something up here. */
325330
static void
@@ -330,17 +335,18 @@ delete_garbage(PyGC_Head *unreachable, PyGC_Head *old)
330335
while (unreachable->gc_next != unreachable) {
331336
PyGC_Head *gc = unreachable->gc_next;
332337
PyObject *op = PyObject_FROM_GC(gc);
333-
/*
334-
PyList_Append(garbage, op);
335-
*/
336-
if ((clear = op->ob_type->tp_clear) != NULL) {
337-
Py_INCREF(op);
338-
clear((PyObject *)op);
339-
Py_DECREF(op);
338+
if (debug & DEBUG_SAVEALL) {
339+
PyList_Append(garbage, op);
340+
}
341+
else {
342+
if ((clear = op->ob_type->tp_clear) != NULL) {
343+
Py_INCREF(op);
344+
clear((PyObject *)op);
345+
Py_DECREF(op);
346+
}
340347
}
341-
/* only try to call tp_clear once for each object */
342348
if (unreachable->gc_next == gc) {
343-
/* still alive, move it, it may die later */
349+
/* object is still alive, move it, it may die later */
344350
gc_list_remove(gc);
345351
gc_list_append(gc, old);
346352
}
@@ -425,7 +431,8 @@ collect(PyGC_Head *young, PyGC_Head *old)
425431
if (debug & DEBUG_STATS) {
426432
if (m == 0 && n == 0) {
427433
PySys_WriteStderr("gc: done.\n");
428-
} else {
434+
}
435+
else {
429436
PySys_WriteStderr(
430437
"gc: done, %ld unreachable, %ld uncollectable.\n",
431438
n+m, n);
@@ -438,6 +445,9 @@ collect(PyGC_Head *young, PyGC_Head *old)
438445
handle_finalizers(&finalizers, old);
439446

440447
if (PyErr_Occurred()) {
448+
if (gc_str == NULL) {
449+
gc_str = PyString_FromString("garbage collection");
450+
}
441451
PyErr_WriteUnraisable(gc_str);
442452
Py_FatalError("unexpected exception during garbage collection");
443453
}
@@ -461,15 +471,17 @@ collect_generations(void)
461471
n = collect(&generation2, &generation2);
462472
}
463473
collections1 = 0;
464-
} else if (collections0 > threshold1) {
474+
}
475+
else if (collections0 > threshold1) {
465476
generation = 1;
466477
collections1++;
467478
gc_list_merge(&generation0, &generation1);
468479
if (generation1.gc_next != &generation1) {
469480
n = collect(&generation1, &generation2);
470481
}
471482
collections0 = 0;
472-
} else {
483+
}
484+
else {
473485
generation = 0;
474486
collections0++;
475487
if (generation0.gc_next != &generation0) {
@@ -603,6 +615,7 @@ static char gc_set_debug__doc__[] =
603615
" DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n"
604616
" DEBUG_INSTANCES - Print instance objects.\n"
605617
" DEBUG_OBJECTS - Print objects other than instances.\n"
618+
" DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them.\n"
606619
" DEBUG_LEAK - Debug leaking programs (everything but STATS).\n"
607620
;
608621

@@ -679,14 +692,14 @@ static char gc__doc__ [] =
679692
;
680693

681694
static PyMethodDef GcMethods[] = {
682-
{"enable", gc_enable, METH_VARARGS, gc_enable__doc__},
683-
{"disable", gc_disable, METH_VARARGS, gc_disable__doc__},
695+
{"enable", gc_enable, METH_VARARGS, gc_enable__doc__},
696+
{"disable", gc_disable, METH_VARARGS, gc_disable__doc__},
684697
{"isenabled", gc_isenabled, METH_VARARGS, gc_isenabled__doc__},
685698
{"set_debug", gc_set_debug, METH_VARARGS, gc_set_debug__doc__},
686699
{"get_debug", gc_get_debug, METH_VARARGS, gc_get_debug__doc__},
687700
{"set_threshold", gc_set_thresh, METH_VARARGS, gc_set_thresh__doc__},
688701
{"get_threshold", gc_get_thresh, METH_VARARGS, gc_get_thresh__doc__},
689-
{"collect", gc_collect, METH_VARARGS, gc_collect__doc__},
702+
{"collect", gc_collect, METH_VARARGS, gc_collect__doc__},
690703
{NULL, NULL} /* Sentinel */
691704
};
692705

@@ -705,9 +718,6 @@ initgc(void)
705718
if (garbage == NULL) {
706719
garbage = PyList_New(0);
707720
}
708-
if (gc_str == NULL) {
709-
gc_str = PyString_FromString("garbage collection");
710-
}
711721
PyDict_SetItemString(d, "garbage", garbage);
712722
PyDict_SetItemString(d, "DEBUG_STATS",
713723
PyInt_FromLong(DEBUG_STATS));
@@ -719,6 +729,8 @@ initgc(void)
719729
PyInt_FromLong(DEBUG_INSTANCES));
720730
PyDict_SetItemString(d, "DEBUG_OBJECTS",
721731
PyInt_FromLong(DEBUG_OBJECTS));
732+
PyDict_SetItemString(d, "DEBUG_SAVEALL",
733+
PyInt_FromLong(DEBUG_SAVEALL));
722734
PyDict_SetItemString(d, "DEBUG_LEAK",
723735
PyInt_FromLong(DEBUG_LEAK));
724736
}

0 commit comments

Comments
 (0)