int num_freed = 0; gc_list_init(&wrcb_to_call); /* Clear all weakrefs to the objects in unreachable. If such a weakref * also has a callback, move it into `wrcb_to_call` if the callback * needs to be invoked. Note that we cannot invoke any callbacks until * all weakrefs to unreachable objects are cleared, lest the callback * resurrect an unreachable object via a still-active weakref. We * make another pass over wrcb_to_call, invoking callbacks, after this * pass completes. */ for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyWeakReference **wrlist; op = FROM_GC(gc); assert(IS_TENTATIVELY_UNREACHABLE(op)); next = gc->gc.gc_next; if (! PyType_SUPPORTS_WEAKREFS(op->ob_type)) continue; /* It supports weakrefs. Does it have any? */ wrlist = (PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(op); /* `op` may have some weakrefs. March over the list, clear * all the weakrefs, and move the weakrefs with callbacks * that must be called into wrcb_to_call. */ for (wr = *wrlist; wr != NULL; wr = *wrlist) { PyGC_Head *wrasgc; /* AS_GC(wr) */ /* _PyWeakref_ClearRef clears the weakref but leaves * the callback pointer intact. Obscure: it also * changes *wrlist. */ assert(wr->wr_object == op); _PyWeakref_ClearRef(wr); assert(wr->wr_object == Py_None); if (wr->wr_callback == NULL) continue; /* no callback */ /* Headache time. `op` is going away, and is weakly referenced by * `wr`, which has a callback. Should the callback be invoked? If wr * is also trash, no: * * 1. There's no need to call it. The object and the weakref are * both going away, so it's legitimate to pretend the weakref is * going away first. The user has to ensure a weakref outlives its * referent if they want a guarantee that the wr callback will get * invoked. * * 2. It may be catastrophic to call it. If the callback is also in * cyclic trash (CT), then although the CT is unreachable from * outside the current generation, CT may be reachable from the * callback. Then the callback could resurrect insane objects. * * Since the callback is never needed and may be unsafe in this case, * wr is simply left in the unreachable set. Note that because we * already called _PyWeakref_ClearRef(wr), its callback will never * trigger. * * OTOH, if wr isn't part of CT, we should invoke the callback: the * weakref outlived the trash. Note that since wr isn't CT in this * case, its callback can't be CT either -- wr acted as an external * root to this generation, and therefore its callback did too. So * nothing in CT is reachable from the callback either, so it's hard * to imagine how calling it later could create a problem for us. wr * is moved to wrcb_to_call in this case. */ if (IS_TENTATIVELY_UNREACHABLE(wr)) continue; assert(IS_REACHABLE(wr)); /* Create a new reference so that wr can't go away * before we can process it again. */ Py_INCREF(wr); /* Move wr to wrcb_to_call, for the next pass. */ wrasgc = AS_GC(wr); assert(wrasgc != next); /* wrasgc is reachable, but next isn't, so they can't be the same */ gc_list_move(wrasgc, &wrcb_to_call); } } /* Invoke the callbacks we decided to honor. It's safe to invoke them * because they can't reference unreachable objects. */ while (! gc_list_is_empty(&wrcb_to_call)) { PyObject *temp; PyObject *callback; gc = wrcb_to_call.gc.gc_next; op = FROM_GC(gc); assert(IS_REACHABLE(op)); assert(PyWeakref_Check(op)); wr = (PyWeakReference *)op; callback = wr->wr_callback; assert(callback != NULL); /* copy-paste of weakrefobject.c's handle_callback() */ temp = PyObject_CallFunctionObjArgs(callback, wr, NULL); if (temp == NULL) PyErr_WriteUnraisable(callback); else Py_DECREF(temp); /* Give up the reference we created in the first pass. When * op's refcount hits 0 (which it may or may not do right now), * op's tp_dealloc will decref op->wr_callback too. Note * that the refcount probably will hit 0 now, and because this * weakref was reachable to begin with, gc didn't already * add it to its count of freed objects. Example: a reachable * weak value dict maps some key to this reachable weakref. * The callback removes this key->weakref mapping from the * dict, leaving no other references to the weakref (excepting * ours). */ Py_DECREF(op); if (wrcb_to_call.gc.gc_next == gc) { /* object is still alive -- move it */ gc_list_move(gc, old); } else ++num_freed; } return num_freed;} static voiddebug_instance(char *msg, PyInstanceObject *inst){ char *cname; /* simple version of instance_repr */ PyObject *classname = inst->in_class->cl_name; if (classname != NULL && PyString_Check(classname)) cname = PyString_AsString(classname); else cname = "?"; PySys_WriteStderr("gc: %.100s <%.100s instance at %p>\n", msg, cname, inst);} static voiddebug_cycle(char *msg, PyObject *op){ if ((debug & DEBUG_INSTANCES) && PyInstance_Check(op)) { debug_instance(msg, (PyInstanceObject *)op); } else if (debug & DEBUG_OBJECTS) { PySys_WriteStderr("gc: %.100s <%.100s %p>\n", msg, op->ob_type->tp_name, op); }} /* Handle uncollectable garbage (cycles with finalizers, and stuff reachable * only from such cycles). * If DEBUG_SAVEALL, all objects in finalizers are appended to the module * garbage list (a Python list), else only the objects in finalizers with * __del__ methods are appended to garbage. All objects in finalizers are * merged into the old list regardless. * Returns 0 if all OK, <0 on error (out of memory to grow the garbage list). * The finalizers list is made empty on a successful return. */static inthandle_finalizers(PyGC_Head *finalizers, PyGC_Head *old){ PyGC_Head *gc = finalizers->gc.gc_next; if (garbage == NULL) { garbage = PyList_New(0); if (garbage == NULL) Py_FatalError("gc couldn't create gc.garbage list"); } for (; gc != finalizers; gc = gc->gc.gc_next) { PyObject *op = FROM_GC(gc); if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) { if (PyList_Append(garbage, op) < 0) return -1; } } gc_list_merge(finalizers, old); return 0;} /* Break reference cycles by clearing the containers involved. This is * tricky business as the lists can be changing and we don't know which * objects may be freed. It is possible I screwed something up here. */static voiddelete_garbage(PyGC_Head *collectable, PyGC_Head *old){ inquiry clear; while (!gc_list_is_empty(collectable)) { PyGC_Head *gc = collectable->gc.gc_next; PyObject *op = FROM_GC(gc); assert(IS_TENTATIVELY_UNREACHABLE(op)); if (debug & DEBUG_SAVEALL) { PyList_Append(garbage, op); } else { if ((clear = op->ob_type->tp_clear) != NULL) { Py_INCREF(op); clear(op); Py_DECREF(op); } } if (collectable->gc.gc_next == gc) { /* object is still alive, move it, it may die later */ gc_list_move(gc, old); gc->gc.gc_refs = GC_REACHABLE; } }} /* This is the main function. Read this to understand how the * collection process works. */static Py_ssize_tcollect(int generation){ int i; Py_ssize_t m = 0; /* # objects collected */ Py_ssize_t n = 0; /* # unreachable objects that couldn't be collected */ PyGC_Head *young; /* the generation we are examining */ PyGC_Head *old; /* next older generation */ PyGC_Head unreachable; /* non-problematic unreachable trash */ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ PyGC_Head *gc; double t1 = 0.0; if (delstr == NULL) { delstr = PyString_InternFromString("__del__"); if (delstr == NULL) Py_FatalError("gc couldn't allocate \"__del__\""); } if (debug & DEBUG_STATS) { if (tmod != NULL) { PyObject *f = PyObject_CallMethod(tmod, "time", NULL); if (f == NULL) { PyErr_Clear(); } else { t1 = PyFloat_AsDouble(f); Py_DECREF(f); } } PySys_WriteStderr("gc: collecting generation %d...\n", generation); PySys_WriteStderr("gc: objects in each generation:"); for (i = 0; i < NUM_GENERATIONS; i++) PySys_WriteStderr(" %" PY_FORMAT_SIZE_T "d", gc_list_size(GEN_HEAD(i))); PySys_WriteStderr("\n"); } /* update collection and allocation counters */ if (generation+1 < NUM_GENERATIONS) generations[generation+1].count += 1; for (i = 0; i <= generation; i++) generations[i].count = 0; /* merge younger generations with one we are currently collecting */ for (i = 0; i < generation; i++) { gc_list_merge(GEN_HEAD(i), GEN_HEAD(generation)); } /* handy references */ young = GEN_HEAD(generation); if (generation < NUM_GENERATIONS-1) old = GEN_HEAD(generation+1); else old = young; /* Using ob_refcnt and gc_refs, calculate which objects in the * container set are reachable from outside the set (i.e., have a * refcount greater than 0 when all the references within the * set are taken into account). */ update_refs(young); subtract_refs(young); /* Leave everything reachable from outside young in young, and move * everything else (in young) to unreachable. * NOTE: This used to move the reachable objects into a reachable * set instead. But most things usually turn out to be reachable, * so it's more efficient to move the unreachable things. */ gc_list_init(&unreachable); move_unreachable(young, &unreachable); /* Move reachable objects to next generation. */ if (young != old) gc_list_merge(young, old); /* All objects in unreachable are trash, but objects reachable from * finalizers can't safely be deleted. Python programmers should take * care not to create such things. For Python, finalizers means * instance objects with __del__ methods. Weakrefs with callbacks * can also call arbitrary Python code but they will be dealt with by * handle_weakrefs(). */ gc_list_init(&finalizers); move_finalizers(&unreachable, &finalizers); /* finalizers contains the unreachable objects with a finalizer; * unreachable objects reachable *from* those are also uncollectable, * and we move those into the finalizers list too. */ move_finalizer_reachable(&finalizers); /* Collect statistics on collectable objects found and print * debugging information. */ for (gc = unreachable.gc.gc_next; gc != &unreachable; gc = gc->gc.gc_next) { m++; if (debug & DEBUG_COLLECTABLE) { debug_cycle("collectable", FROM_GC(gc)); } if (tmod != NULL && (debug & DEBUG_STATS)) { PyObject *f = PyObject_CallMethod(tmod, "time", NULL); if (f == NULL) { PyErr_Clear(); } else { t1 = PyFloat_AsDouble(f)-t1; Py_DECREF(f); PySys_WriteStderr("gc: %.4fs elapsed.\n", t1); } } } /* Clear weakrefs and invoke callbacks as necessary. */ m += handle_weakrefs(&unreachable, old); /* Call tp_clear on objects in the unreachable set. This will cause * the reference cycles to be broken. It may also cause some objects * in finalizers to be freed. */ delete_garbage(&unreachable, old); /* Collect statistics on uncollectable objects found and print * debugging information. */ for (gc = finalizers.gc.gc_next; gc != &finalizers; gc = gc->gc.gc_next) { n++; if (debug & DEBUG_UNCOLLECTABLE) debug_cycle("uncollectable", FROM_GC(gc)); } if (debug & DEBUG_STATS) { if (m == 0 && n == 0) PySys_WriteStderr("gc: done.\n"); else PySys_WriteStderr( "gc: done, " "%" PY_FORMAT_SIZE_T "d unreachable, " "%" PY_FORMAT_SIZE_T "d uncollectable.\n", n+m, n); } /* Append instances in the uncollectable set to a Python * reachable list of garbage. The programmer has to deal with * this if they insist on creating this type of structure. */ (void)handle_finalizers(&finalizers, old); if (PyErr_Occurred()) { if (gc_str == NULL) gc_str = PyString_FromString("garbage collection"); PyErr_WriteUnraisable(gc_str); Py_FatalError("unexpected exception during garbage collection"); } return n+m;} static Py_ssize_tcollect_generations(void){ int i; Py_ssize_t n = 0; /* Find the oldest generation (higest numbered) where the count * exceeds the threshold. Objects in the that generation and * generations younger than it will be collected. */ for (i = NUM_GENERATIONS-1; i >= 0; i--) { if (generations[i].count > generations[i].threshold) { n = collect(i); break; } } return n;} PyDoc_STRVAR(gc_enable__doc__,"enable() -> None\n""\n""Enable automatic garbage collection.\n"); static PyObject *gc_enable(PyObject *self, PyObject *noargs){ enabled = 1; Py_INCREF(Py_None); return Py_None;} PyDoc_STRVAR(gc_disable__doc__,"disable() -> None\n""\n""Disable automatic garbage collection.\n"); static PyObject *gc_disable(PyObject *self, PyObject *noargs){ enabled = 0; Py_INCREF(Py_None); return Py_None;} PyDoc_STRVAR(gc_isenabled__doc__,"isenabled() -> status\n""\n""Returns true if automatic garbage collection is enabled.\n"); static PyObject *gc_isenabled(PyObject *self, PyObject *noargs){ return PyBool_FromLong((long)enabled);} PyDoc_STRVAR(gc_collect__doc__,"collect([generation]) -> n\n""\n""With no arguments, run a full collection. The optional argument\n""may be an integer specifying which generation to collect. A ValueError\n""is raised if the generation number is invalid.\n\n""The number of unreachable objects is returned.\n"); static PyObject *gc_collect(PyObject *self, PyObject *args, PyObject *kws){ static char *keywords[] = {"generation", NULL}; int genarg = NUM_GENERATIONS - 1; Py_ssize_t n; if (!PyArg_ParseTupleAndKeywords(args, kws, "|i", keywords, &genarg)) return NULL; else if (genarg < 0 || genarg >= NUM_GENERATIONS) { PyErr_SetString(PyExc_ValueError, "invalid generation"); return NULL; } if (collecting) n = 0; /* already collecting, don't do anything */ else { collecting = 1; n = collect(genarg); collecting = 0; } return PyInt_FromSsize_t(n);} PyDoc_STRVAR(gc_set_debug__doc__,"set_debug(flags) -> None\n""\n""Set the garbage collection debugging flags. Debugging information is\n""written to sys.stderr.\n""\n""flags is an integer and can have the following bits turned on:\n""\n"" DEBUG_STATS - Print statistics during collection.\n"" DEBUG_COLLECTABLE - Print collectable objects found.\n"" DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n"" DEBUG_INSTANCES - Print instance objects.\n"" DEBUG_OBJECTS - Print objects other than instances.\n"" DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them.\n"" DEBUG_LEAK - Debug leaking programs (everything but STATS).\n"); static PyObject *gc_set_debug(PyObject *self, PyObject *args){ if (!PyArg_ParseTuple(args, "i:set_debug", &debug)) return NULL; Py_INCREF(Py_None); return Py_None;} Lines 501–1000 of 1390. Previous lines Load more
int num_freed = 0; gc_list_init(&wrcb_to_call); /* Clear all weakrefs to the objects in unreachable. If such a weakref * also has a callback, move it into `wrcb_to_call` if the callback * needs to be invoked. Note that we cannot invoke any callbacks until * all weakrefs to unreachable objects are cleared, lest the callback * resurrect an unreachable object via a still-active weakref. We * make another pass over wrcb_to_call, invoking callbacks, after this * pass completes. */ for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyWeakReference **wrlist; op = FROM_GC(gc); assert(IS_TENTATIVELY_UNREACHABLE(op)); next = gc->gc.gc_next; if (! PyType_SUPPORTS_WEAKREFS(op->ob_type)) continue; /* It supports weakrefs. Does it have any? */ wrlist = (PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(op); /* `op` may have some weakrefs. March over the list, clear * all the weakrefs, and move the weakrefs with callbacks * that must be called into wrcb_to_call. */ for (wr = *wrlist; wr != NULL; wr = *wrlist) { PyGC_Head *wrasgc; /* AS_GC(wr) */ /* _PyWeakref_ClearRef clears the weakref but leaves * the callback pointer intact. Obscure: it also * changes *wrlist. */ assert(wr->wr_object == op); _PyWeakref_ClearRef(wr); assert(wr->wr_object == Py_None); if (wr->wr_callback == NULL) continue; /* no callback */ /* Headache time. `op` is going away, and is weakly referenced by * `wr`, which has a callback. Should the callback be invoked? If wr * is also trash, no: * * 1. There's no need to call it. The object and the weakref are * both going away, so it's legitimate to pretend the weakref is * going away first. The user has to ensure a weakref outlives its * referent if they want a guarantee that the wr callback will get * invoked. * * 2. It may be catastrophic to call it. If the callback is also in * cyclic trash (CT), then although the CT is unreachable from * outside the current generation, CT may be reachable from the * callback. Then the callback could resurrect insane objects. * * Since the callback is never needed and may be unsafe in this case, * wr is simply left in the unreachable set. Note that because we * already called _PyWeakref_ClearRef(wr), its callback will never * trigger. * * OTOH, if wr isn't part of CT, we should invoke the callback: the * weakref outlived the trash. Note that since wr isn't CT in this * case, its callback can't be CT either -- wr acted as an external * root to this generation, and therefore its callback did too. So * nothing in CT is reachable from the callback either, so it's hard * to imagine how calling it later could create a problem for us. wr * is moved to wrcb_to_call in this case. */ if (IS_TENTATIVELY_UNREACHABLE(wr)) continue; assert(IS_REACHABLE(wr)); /* Create a new reference so that wr can't go away * before we can process it again. */ Py_INCREF(wr); /* Move wr to wrcb_to_call, for the next pass. */ wrasgc = AS_GC(wr); assert(wrasgc != next); /* wrasgc is reachable, but next isn't, so they can't be the same */ gc_list_move(wrasgc, &wrcb_to_call); } } /* Invoke the callbacks we decided to honor. It's safe to invoke them * because they can't reference unreachable objects. */ while (! gc_list_is_empty(&wrcb_to_call)) { PyObject *temp; PyObject *callback; gc = wrcb_to_call.gc.gc_next; op = FROM_GC(gc); assert(IS_REACHABLE(op)); assert(PyWeakref_Check(op)); wr = (PyWeakReference *)op; callback = wr->wr_callback; assert(callback != NULL); /* copy-paste of weakrefobject.c's handle_callback() */ temp = PyObject_CallFunctionObjArgs(callback, wr, NULL); if (temp == NULL) PyErr_WriteUnraisable(callback); else Py_DECREF(temp); /* Give up the reference we created in the first pass. When * op's refcount hits 0 (which it may or may not do right now), * op's tp_dealloc will decref op->wr_callback too. Note * that the refcount probably will hit 0 now, and because this * weakref was reachable to begin with, gc didn't already * add it to its count of freed objects. Example: a reachable * weak value dict maps some key to this reachable weakref. * The callback removes this key->weakref mapping from the * dict, leaving no other references to the weakref (excepting * ours). */ Py_DECREF(op); if (wrcb_to_call.gc.gc_next == gc) { /* object is still alive -- move it */ gc_list_move(gc, old); } else ++num_freed; } return num_freed; } static void debug_instance(char *msg, PyInstanceObject *inst) { char *cname; /* simple version of instance_repr */ PyObject *classname = inst->in_class->cl_name; if (classname != NULL && PyString_Check(classname)) cname = PyString_AsString(classname); else cname = "?"; PySys_WriteStderr("gc: %.100s <%.100s instance at %p>\n", msg, cname, inst); } static void debug_cycle(char *msg, PyObject *op) { if ((debug & DEBUG_INSTANCES) && PyInstance_Check(op)) { debug_instance(msg, (PyInstanceObject *)op); } else if (debug & DEBUG_OBJECTS) { PySys_WriteStderr("gc: %.100s <%.100s %p>\n", msg, op->ob_type->tp_name, op); } } /* Handle uncollectable garbage (cycles with finalizers, and stuff reachable * only from such cycles). * If DEBUG_SAVEALL, all objects in finalizers are appended to the module * garbage list (a Python list), else only the objects in finalizers with * __del__ methods are appended to garbage. All objects in finalizers are * merged into the old list regardless. * Returns 0 if all OK, <0 on error (out of memory to grow the garbage list). * The finalizers list is made empty on a successful return. */ static int handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old) { PyGC_Head *gc = finalizers->gc.gc_next; if (garbage == NULL) { garbage = PyList_New(0); if (garbage == NULL) Py_FatalError("gc couldn't create gc.garbage list"); } for (; gc != finalizers; gc = gc->gc.gc_next) { PyObject *op = FROM_GC(gc); if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) { if (PyList_Append(garbage, op) < 0) return -1; } } gc_list_merge(finalizers, old); return 0; } /* Break reference cycles by clearing the containers involved. This is * tricky business as the lists can be changing and we don't know which * objects may be freed. It is possible I screwed something up here. */ static void delete_garbage(PyGC_Head *collectable, PyGC_Head *old) { inquiry clear; while (!gc_list_is_empty(collectable)) { PyGC_Head *gc = collectable->gc.gc_next; PyObject *op = FROM_GC(gc); assert(IS_TENTATIVELY_UNREACHABLE(op)); if (debug & DEBUG_SAVEALL) { PyList_Append(garbage, op); } else { if ((clear = op->ob_type->tp_clear) != NULL) { Py_INCREF(op); clear(op); Py_DECREF(op); } } if (collectable->gc.gc_next == gc) { /* object is still alive, move it, it may die later */ gc_list_move(gc, old); gc->gc.gc_refs = GC_REACHABLE; } } } /* This is the main function. Read this to understand how the * collection process works. */ static Py_ssize_t collect(int generation) { int i; Py_ssize_t m = 0; /* # objects collected */ Py_ssize_t n = 0; /* # unreachable objects that couldn't be collected */ PyGC_Head *young; /* the generation we are examining */ PyGC_Head *old; /* next older generation */ PyGC_Head unreachable; /* non-problematic unreachable trash */ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ PyGC_Head *gc; double t1 = 0.0; if (delstr == NULL) { delstr = PyString_InternFromString("__del__"); if (delstr == NULL) Py_FatalError("gc couldn't allocate \"__del__\""); } if (debug & DEBUG_STATS) { if (tmod != NULL) { PyObject *f = PyObject_CallMethod(tmod, "time", NULL); if (f == NULL) { PyErr_Clear(); } else { t1 = PyFloat_AsDouble(f); Py_DECREF(f); } } PySys_WriteStderr("gc: collecting generation %d...\n", generation); PySys_WriteStderr("gc: objects in each generation:"); for (i = 0; i < NUM_GENERATIONS; i++) PySys_WriteStderr(" %" PY_FORMAT_SIZE_T "d", gc_list_size(GEN_HEAD(i))); PySys_WriteStderr("\n"); } /* update collection and allocation counters */ if (generation+1 < NUM_GENERATIONS) generations[generation+1].count += 1; for (i = 0; i <= generation; i++) generations[i].count = 0; /* merge younger generations with one we are currently collecting */ for (i = 0; i < generation; i++) { gc_list_merge(GEN_HEAD(i), GEN_HEAD(generation)); } /* handy references */ young = GEN_HEAD(generation); if (generation < NUM_GENERATIONS-1) old = GEN_HEAD(generation+1); else old = young; /* Using ob_refcnt and gc_refs, calculate which objects in the * container set are reachable from outside the set (i.e., have a * refcount greater than 0 when all the references within the * set are taken into account). */ update_refs(young); subtract_refs(young); /* Leave everything reachable from outside young in young, and move * everything else (in young) to unreachable. * NOTE: This used to move the reachable objects into a reachable * set instead. But most things usually turn out to be reachable, * so it's more efficient to move the unreachable things. */ gc_list_init(&unreachable); move_unreachable(young, &unreachable); /* Move reachable objects to next generation. */ if (young != old) gc_list_merge(young, old); /* All objects in unreachable are trash, but objects reachable from * finalizers can't safely be deleted. Python programmers should take * care not to create such things. For Python, finalizers means * instance objects with __del__ methods. Weakrefs with callbacks * can also call arbitrary Python code but they will be dealt with by * handle_weakrefs(). */ gc_list_init(&finalizers); move_finalizers(&unreachable, &finalizers); /* finalizers contains the unreachable objects with a finalizer; * unreachable objects reachable *from* those are also uncollectable, * and we move those into the finalizers list too. */ move_finalizer_reachable(&finalizers); /* Collect statistics on collectable objects found and print * debugging information. */ for (gc = unreachable.gc.gc_next; gc != &unreachable; gc = gc->gc.gc_next) { m++; if (debug & DEBUG_COLLECTABLE) { debug_cycle("collectable", FROM_GC(gc)); } if (tmod != NULL && (debug & DEBUG_STATS)) { PyObject *f = PyObject_CallMethod(tmod, "time", NULL); if (f == NULL) { PyErr_Clear(); } else { t1 = PyFloat_AsDouble(f)-t1; Py_DECREF(f); PySys_WriteStderr("gc: %.4fs elapsed.\n", t1); } } } /* Clear weakrefs and invoke callbacks as necessary. */ m += handle_weakrefs(&unreachable, old); /* Call tp_clear on objects in the unreachable set. This will cause * the reference cycles to be broken. It may also cause some objects * in finalizers to be freed. */ delete_garbage(&unreachable, old); /* Collect statistics on uncollectable objects found and print * debugging information. */ for (gc = finalizers.gc.gc_next; gc != &finalizers; gc = gc->gc.gc_next) { n++; if (debug & DEBUG_UNCOLLECTABLE) debug_cycle("uncollectable", FROM_GC(gc)); } if (debug & DEBUG_STATS) { if (m == 0 && n == 0) PySys_WriteStderr("gc: done.\n"); else PySys_WriteStderr( "gc: done, " "%" PY_FORMAT_SIZE_T "d unreachable, " "%" PY_FORMAT_SIZE_T "d uncollectable.\n", n+m, n); } /* Append instances in the uncollectable set to a Python * reachable list of garbage. The programmer has to deal with * this if they insist on creating this type of structure. */ (void)handle_finalizers(&finalizers, old); if (PyErr_Occurred()) { if (gc_str == NULL) gc_str = PyString_FromString("garbage collection"); PyErr_WriteUnraisable(gc_str); Py_FatalError("unexpected exception during garbage collection"); } return n+m; } static Py_ssize_t collect_generations(void) { int i; Py_ssize_t n = 0; /* Find the oldest generation (higest numbered) where the count * exceeds the threshold. Objects in the that generation and * generations younger than it will be collected. */ for (i = NUM_GENERATIONS-1; i >= 0; i--) { if (generations[i].count > generations[i].threshold) { n = collect(i); break; } } return n; } PyDoc_STRVAR(gc_enable__doc__, "enable() -> None\n" "\n" "Enable automatic garbage collection.\n"); static PyObject * gc_enable(PyObject *self, PyObject *noargs) { enabled = 1; Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(gc_disable__doc__, "disable() -> None\n" "\n" "Disable automatic garbage collection.\n"); static PyObject * gc_disable(PyObject *self, PyObject *noargs) { enabled = 0; Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(gc_isenabled__doc__, "isenabled() -> status\n" "\n" "Returns true if automatic garbage collection is enabled.\n"); static PyObject * gc_isenabled(PyObject *self, PyObject *noargs) { return PyBool_FromLong((long)enabled); } PyDoc_STRVAR(gc_collect__doc__, "collect([generation]) -> n\n" "\n" "With no arguments, run a full collection. The optional argument\n" "may be an integer specifying which generation to collect. A ValueError\n" "is raised if the generation number is invalid.\n\n" "The number of unreachable objects is returned.\n"); static PyObject * gc_collect(PyObject *self, PyObject *args, PyObject *kws) { static char *keywords[] = {"generation", NULL}; int genarg = NUM_GENERATIONS - 1; Py_ssize_t n; if (!PyArg_ParseTupleAndKeywords(args, kws, "|i", keywords, &genarg)) return NULL; else if (genarg < 0 || genarg >= NUM_GENERATIONS) { PyErr_SetString(PyExc_ValueError, "invalid generation"); return NULL; } if (collecting) n = 0; /* already collecting, don't do anything */ else { collecting = 1; n = collect(genarg); collecting = 0; } return PyInt_FromSsize_t(n); } PyDoc_STRVAR(gc_set_debug__doc__, "set_debug(flags) -> None\n" "\n" "Set the garbage collection debugging flags. Debugging information is\n" "written to sys.stderr.\n" "\n" "flags is an integer and can have the following bits turned on:\n" "\n" " DEBUG_STATS - Print statistics during collection.\n" " DEBUG_COLLECTABLE - Print collectable objects found.\n" " DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n" " DEBUG_INSTANCES - Print instance objects.\n" " DEBUG_OBJECTS - Print objects other than instances.\n" " DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them.\n" " DEBUG_LEAK - Debug leaking programs (everything but STATS).\n"); static PyObject * gc_set_debug(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "i:set_debug", &debug)) return NULL; Py_INCREF(Py_None); return Py_None; }