📄 gcmodule.c
字号:
debug_cycle("collectable", FROM_GC(gc));
}
}
/* call tp_clear on objects in the collectable 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, %ld unreachable, %ld 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. */
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");
}
allocated = 0;
return n+m;
}
static long
collect_generations(void)
{
#ifndef SYMBIAN
static long collections0 = 0;
static long collections1 = 0;
#else
#define collections0 (GC_GLOBALS->collect_generations_collections0)
#define collections1 (GC_GLOBALS->collect_generations_collections1)
#endif
long n = 0;
if (collections1 > threshold2) {
generation = 2;
gc_list_merge(&_PyGC_generation0, &generation2);
gc_list_merge(&generation1, &generation2);
if (generation2.gc.gc_next != &generation2) {
n = collect(&generation2, &generation2);
}
collections1 = 0;
}
else if (collections0 > threshold1) {
generation = 1;
collections1++;
gc_list_merge(&_PyGC_generation0, &generation1);
if (generation1.gc.gc_next != &generation1) {
n = collect(&generation1, &generation2);
}
collections0 = 0;
}
else {
generation = 0;
collections0++;
if (_PyGC_generation0.gc.gc_next != &_PyGC_generation0) {
n = collect(&_PyGC_generation0, &generation1);
}
}
return n;
}
static char gc_enable__doc__[] =
"enable() -> None\n"
"\n"
"Enable automatic garbage collection.\n"
;
static PyObject *
gc_enable(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":enable")) /* check no args */
return NULL;
enabled = 1;
Py_INCREF(Py_None);
return Py_None;
}
static char gc_disable__doc__[] =
"disable() -> None\n"
"\n"
"Disable automatic garbage collection.\n"
;
static PyObject *
gc_disable(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":disable")) /* check no args */
return NULL;
enabled = 0;
Py_INCREF(Py_None);
return Py_None;
}
static char gc_isenabled__doc__[] =
"isenabled() -> status\n"
"\n"
"Returns true if automatic garbage collection is enabled.\n"
;
static PyObject *
gc_isenabled(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":isenabled")) /* check no args */
return NULL;
return Py_BuildValue("i", enabled);
}
static char gc_collect__doc__[] =
"collect() -> n\n"
"\n"
"Run a full collection. The number of unreachable objects is returned.\n"
;
static PyObject *
gc_collect(PyObject *self, PyObject *args)
{
long n;
if (!PyArg_ParseTuple(args, ":collect")) /* check no args */
return NULL;
if (collecting) {
n = 0; /* already collecting, don't do anything */
}
else {
collecting = 1;
generation = 2;
gc_list_merge(&_PyGC_generation0, &generation2);
gc_list_merge(&generation1, &generation2);
n = collect(&generation2, &generation2);
collecting = 0;
}
return Py_BuildValue("l", n);
}
static char 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;
}
static char gc_get_debug__doc__[] =
"get_debug() -> flags\n"
"\n"
"Get the garbage collection debugging flags.\n"
;
static PyObject *
gc_get_debug(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":get_debug")) /* no args */
return NULL;
return Py_BuildValue("i", debug);
}
static char gc_set_thresh__doc__[] =
"set_threshold(threshold0, [threshold1, threshold2]) -> None\n"
"\n"
"Sets the collection thresholds. Setting threshold0 to zero disables\n"
"collection.\n"
;
static PyObject *
gc_set_thresh(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, "i|ii:set_threshold", &threshold0,
&threshold1, &threshold2))
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static char gc_get_thresh__doc__[] =
"get_threshold() -> (threshold0, threshold1, threshold2)\n"
"\n"
"Return the current collection thresholds\n"
;
static PyObject *
gc_get_thresh(PyObject *self, PyObject *args)
{
if (!PyArg_ParseTuple(args, ":get_threshold")) /* no args */
return NULL;
return Py_BuildValue("(iii)", threshold0, threshold1, threshold2);
}
static int
referrersvisit(PyObject* obj, PyObject *objs)
{
int i;
for (i = 0; i < PyTuple_GET_SIZE(objs); i++)
if (PyTuple_GET_ITEM(objs, i) == obj)
return 1;
return 0;
}
static int
gc_referrers_for(PyObject *objs, PyGC_Head *list, PyObject *resultlist)
{
PyGC_Head *gc;
PyObject *obj;
traverseproc traverse;
for (gc = list->gc.gc_next; gc != list; gc = gc->gc.gc_next) {
obj = FROM_GC(gc);
traverse = obj->ob_type->tp_traverse;
if (obj == objs || obj == resultlist)
continue;
if (traverse(obj, (visitproc)referrersvisit, objs)) {
if (PyList_Append(resultlist, obj) < 0)
return 0; /* error */
}
}
return 1; /* no error */
}
static char gc_get_referrers__doc__[]=
"get_referrers(*objs) -> list\n\
Return the list of objects that directly refer to any of objs.";
static PyObject *
gc_get_referrers(PyObject *self, PyObject *args)
{
PyObject *result = PyList_New(0);
if (!(gc_referrers_for(args, &_PyGC_generation0, result) &&
gc_referrers_for(args, &generation1, result) &&
gc_referrers_for(args, &generation2, result))) {
Py_DECREF(result);
return NULL;
}
return result;
}
static char gc_get_objects__doc__[] =
"get_objects() -> [...]\n"
"\n"
"Return a list of objects tracked by the collector (excluding the list\n"
"returned).\n"
;
/* appending objects in a GC list to a Python list */
static int
append_objects(PyObject *py_list, PyGC_Head *gc_list)
{
PyGC_Head *gc;
for (gc = gc_list->gc.gc_next; gc != gc_list; gc = gc->gc.gc_next) {
PyObject *op = FROM_GC(gc);
if (op != py_list) {
if (PyList_Append(py_list, op)) {
return -1; /* exception */
}
}
}
return 0;
}
static PyObject *
gc_get_objects(PyObject *self, PyObject *args)
{
PyObject* result;
if (!PyArg_ParseTuple(args, ":get_objects")) /* check no args */
return NULL;
result = PyList_New(0);
if (result == NULL) {
return NULL;
}
if (append_objects(result, &_PyGC_generation0) ||
append_objects(result, &generation1) ||
append_objects(result, &generation2)) {
Py_DECREF(result);
return NULL;
}
return result;
}
static char gc__doc__ [] =
#ifndef SYMBIAN
"This module provides access to the garbage collector for reference cycles.\n"
"\n"
"enable() -- Enable automatic garbage collection.\n"
"disable() -- Disable automatic garbage collection.\n"
"isenabled() -- Returns true if automatic collection is enabled.\n"
"collect() -- Do a full collection right now.\n"
"set_debug() -- Set debugging flags.\n"
"get_debug() -- Get debugging flags.\n"
"set_threshold() -- Set the collection thresholds.\n"
"get_threshold() -- Return the current the collection thresholds.\n"
"get_objects() -- Return a list of all objects tracked by the collector.\n"
"get_referrers() -- Return the list of objects that refer to an object.\n"
;
#else
"";
#endif
#ifndef SYMBIAN
static PyMethodDef GcMethods[] = {
{"enable", gc_enable, METH_VARARGS, gc_enable__doc__},
{"disable", gc_disable, METH_VARARGS, gc_disable__doc__},
{"isenabled", gc_isenabled, METH_VARARGS, gc_isenabled__doc__},
{"set_debug", gc_set_debug, METH_VARARGS, gc_set_debug__doc__},
{"get_debug", gc_get_debug, METH_VARARGS, gc_get_debug__doc__},
{"set_threshold", gc_set_thresh, METH_VARARGS, gc_set_thresh__doc__},
{"get_threshold", gc_get_thresh, METH_VARARGS, gc_get_thresh__doc__},
{"collect", gc_collect, METH_VARARGS, gc_collect__doc__},
{"get_objects", gc_get_objects,METH_VARARGS, gc_get_objects__doc__},
{"get_referrers", gc_get_referrers, METH_VARARGS,
gc_get_referrers__doc__},
{NULL, NULL} /* Sentinel */
};
#else
static const PyMethodDef GcMethods[] = {
{"enable", gc_enable, METH_VARARGS, NULL},
{"disable", gc_disable, METH_VARARGS, NULL},
{"isenabled", gc_isenabled, METH_VARARGS, NULL},
{"set_debug", gc_set_debug, METH_VARARGS, NULL},
{"get_debug", gc_get_debug, METH_VARARGS, NULL},
{"set_threshold", gc_set_thresh, METH_VARARGS, NULL},
{"get_threshold", gc_get_thresh, METH_VARARGS, NULL},
{"collect", gc_collect, METH_VARARGS, NULL},
{"get_objects", gc_get_objects,METH_VARARGS, NULL},
{"get_referrers", gc_get_referrers, METH_VARARGS, NULL},
{NULL, NULL} /* Sentinel */
};
#endif
void
initgc(void)
{
PyObject *m;
PyObject *d;
m = Py_InitModule4("gc",
GcMethods,
gc__doc__,
NULL,
PYTHON_API_VERSION);
d = PyModule_GetDict(m);
if (garbage == NULL) {
garbage = PyList_New(0);
}
PyDict_SetItemString(d, "garbage", garbage);
PyDict_SetItemString(d, "DEBUG_STATS",
PyInt_FromLong(DEBUG_STATS));
PyDict_SetItemString(d, "DEBUG_COLLECTABLE",
PyInt_FromLong(DEBUG_COLLECTABLE));
PyDict_SetItemString(d, "DEBUG_UNCOLLECTABLE",
PyInt_FromLong(DEBUG_UNCOLLECTABLE));
PyDict_SetItemString(d, "DEBUG_INSTANCES",
PyInt_FromLong(DEBUG_INSTANCES));
PyDict_SetItemString(d, "DEBUG_OBJECTS",
PyInt_FromLong(DEBUG_OBJECTS));
PyDict_SetItemString(d, "DEBUG_SAVEALL",
PyInt_FromLong(DEBUG_SAVEALL));
PyDict_SetItemString(d, "DEBUG_LEAK",
PyInt_FromLong(DEBUG_LEAK));
}
/* for debugging */
void _PyGC_Dump(PyGC_Head *g)
{
_PyObject_Dump(FROM_GC(g));
}
#endif /* WITH_CYCLE_GC */
/* extension modules might be compiled with GC support so these
functions must always be available */
DL_EXPORT(void)
_PyObject_GC_Track(PyObject *op)
{
_PyObject_GC_TRACK(op);
}
DL_EXPORT(void)
_PyObject_GC_UnTrack(PyObject *op)
{
#ifdef WITH_CYCLE_GC
PyGC_Head *gc = AS_GC(op);
if (gc->gc.gc_next != NULL)
_PyObject_GC_UNTRACK(op);
#endif
}
DL_EXPORT(PyObject *)
_PyObject_GC_Malloc(PyTypeObject *tp, int nitems)
{
PyObject *op;
const size_t basicsize = _PyObject_VAR_SIZE(tp, nitems);
#ifdef WITH_CYCLE_GC
const size_t nbytes = sizeof(PyGC_Head) + basicsize;
PyGC_Head *g = PyObject_MALLOC(nbytes);
if (g == NULL)
return (PyObject *)PyErr_NoMemory();
g->gc.gc_next = NULL;
#ifdef SYMBIAN
if (GC_GLOBALS == NULL)
init_gc_globals();
#endif
allocated++;
if (allocated > threshold0 &&
enabled &&
threshold0 &&
!collecting &&
!PyErr_Occurred()) {
collecting = 1;
collect_generations();
collecting = 0;
}
op = FROM_GC(g);
#else
op = PyObject_MALLOC(basicsize);
if (op == NULL)
return (PyObject *)PyErr_NoMemory();
#endif
return op;
}
DL_EXPORT(PyObject *)
_PyObject_GC_New(PyTypeObject *tp)
{
PyObject *op = _PyObject_GC_Malloc(tp, 0);
if (op != NULL)
op = PyObject_INIT(op, tp);
return op;
}
DL_EXPORT(PyVarObject *)
_PyObject_GC_NewVar(PyTypeObject *tp, int nitems)
{
PyVarObject *op = (PyVarObject *) _PyObject_GC_Malloc(tp, nitems);
if (op != NULL)
op = PyObject_INIT_VAR(op, tp, nitems);
return op;
}
DL_EXPORT(PyVarObject *)
_PyObject_GC_Resize(PyVarObject *op, int nitems)
{
const size_t basicsize = _PyObject_VAR_SIZE(op->ob_type, nitems);
#ifdef WITH_CYCLE_GC
PyGC_Head *g = AS_GC(op);
g = PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize);
if (g == NULL)
return (PyVarObject *)PyErr_NoMemory();
op = (PyVarObject *) FROM_GC(g);
#else
op = PyObject_REALLOC(op, basicsize);
if (op == NULL)
return (PyVarObject *)PyErr_NoMemory();
#endif
op->ob_size = nitems;
return op;
}
DL_EXPORT(void)
_PyObject_GC_Del(PyObject *op)
{
#ifdef WITH_CYCLE_GC
PyGC_Head *g = AS_GC(op);
if (g->gc.gc_next != NULL)
gc_list_remove(g);
if (allocated > 0) {
allocated--;
}
PyObject_FREE(g);
#else
PyObject_FREE(op);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -