CPython에는 서로 밀접하게 연결된 두 가지 유형의 객체가 있습니다. 각각을 만들고, 다른에 대한 참조를 유지하기 때문에 내 테스트 스크립트를 사용CPython에서 직접 참조주기를 끊는 방법
는#include <Python.h>
#include <structmember.h>
typedef struct pyt PYT;
struct pyt { PyObject_HEAD PYT *other; };
static void dealloc (PYT *self) {
Py_CLEAR(self->other);
printf("dealloc object at %p\n", self);
PyObject_GC_Del(self);
}
static PyTypeObject Pyt2Type = {
PyObject_HEAD_INIT(NULL)
0, "pyt.Pyt2", sizeof(PYT), 0,
(destructor) dealloc
};
static PyObject * new (PyTypeObject *type, PyObject *args, PyObject *kwds) {
PYT *self = PyObject_GC_New(PYT, type);
if (!self) return NULL;
self->other = PyObject_GC_New(PYT, &Pyt2Type);
if (!self->other) { Py_DECREF(self); return NULL; }
return Py_INCREF(self), self->other->other = self, (PyObject *) self;
}
static PyTypeObject Pyt1Type = {
PyObject_HEAD_INIT(NULL)
0, "pyt.Pyt1", sizeof(PYT), 0,
(destructor) dealloc
};
static int traverse (PYT *self, visitproc visit, void *arg) {
Py_VISIT(self->other);
return 0;
}
static int clear (PYT *self) {
Py_CLEAR(self->other);
return 0;
}
static PyMemberDef members[] = {
{"other", T_OBJECT, offsetof(PYT, other), RO, "other"},
{ NULL }
};
static PyMethodDef methods[] = {{ NULL }};
PyMODINIT_FUNC initpyt (void) {
PyObject* m;
Pyt1Type.tp_flags = Pyt2Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC;
Pyt1Type.tp_traverse = Pyt2Type.tp_traverse = (traverseproc) traverse;
Pyt1Type.tp_clear = Pyt2Type.tp_clear = (inquiry) clear;
Pyt1Type.tp_members = Pyt2Type.tp_members = members;
Pyt1Type.tp_new = new;
if (PyType_Ready(&Pyt1Type) < 0) return;
if (PyType_Ready(&Pyt2Type) < 0) return;
m = Py_InitModule("pyt", methods);
Py_INCREF(&Pyt1Type), PyModule_AddObject(m, "Pyt", (PyObject *) &Pyt1Type);
}
from distutils.core import Extension, setup
import sys, gc
sys.argv.extend(["build_ext", "-i"])
setup(ext_modules = [Extension('pyt', ['pyt.c'])])
from pyt import Pyt
pyt = Pyt()
print pyt, sys.getrefcount(pyt)
pyt = pyt.other
print pyt, sys.getrefcount(pyt)
del pyt
gc.collect()
나는
<pyt.Pyt1 object at 0x7fbc26540138> 3
<pyt.Pyt2 object at 0x7fbc26540150> 3
객체가 마지막에 삭제되지 않습니다 같은 출력을 얻을 닫힌 사이클. 다른 코드에서는 두 가지 모두가 0의 참조를 가질 때까지 객체를 보관하는 방식을 사용했습니다. 이는 나쁜 습관으로 의심됩니다. 이제는 여기에서 가비지 컬렉터를 사용해 보았지만 여전히 오브젝트는 수집되지 않았습니다.
여기에 무슨 문제가 있습니까? 내가 놓친 게 무엇입니까?
의 출력으로
; 여전히 컬렉션이 없습니다. – tynn