Python 2.7的doc的两个部分提到为扩展模块中定义的容器对象添加循环垃圾收集(CGC)支持。
Python/C API Reference Manual给出了两条规则,即
- 必须使用
分配对象的内存PyObject_GC_New()
或PyObject_GC_NewVar()
- 一旦初始化了可能包含对其他容器的引用的所有字段,就必须调用
醇>PyObject_GC_Track()
。
而在Extending and Embedding the Python Interpreter中,对于Noddy
示例,似乎添加Py_TPFLAGS_HAVE_GC
标记并填充tp_traverse
和tp_clear
广告位就足以启用CGC支持。以上两条规则根本没有实施。
当我修改Noddy
示例以实际遵循PyObject_GC_New()
/ PyObject_GC_Del()
和PyObject_Track()
/ PyObject_GC_UnTrack()
的规则时,令人惊讶地提出断言错误说,
Modules / gcmodule.c:348:visit_decref:断言“gc-> gc.gc_refs!= 0”失败。 refcount太小了
这导致我对实施CGC的正确/安全方式感到困惑。任何人都可以提供建议,或者最好是一个容器对象的整洁的示例吗?
答案 0 :(得分:3)
我自己在C API方面没有足够的经验给你任何建议,但Python容器实现本身有很多例子。
就个人而言,我首先从元组实现开始,因为它是不可变的:Objects/tupleobject.c。然后转到dict
,list
和set
实现,以获取有关可变容器的更多说明:
我不禁注意到,PyObject_GC_New()
,PyObject_GC_NewVar()
和PyObject_GC_Track()
的呼叫始终存在,并且设置了Py_TPFLAGS_HAVE_GC
。
答案 1 :(得分:1)
在大多数正常情况下,您不需要自己进行跟踪/取消跟踪。这在文档中有描述,但并未明确说明。在Noddy
example的情况下,你绝对不会。
简短版本是TypeObject包含两个函数指针:tp_alloc
和tp_free
。默认情况下,tp_alloc
会在创建类时调用所有正确的函数(如果已设置Py_TPFLAGS_HAVE_GC
),并且tp_free
会在销毁时取消该类。
Noddy documentation says(在本节末尾):
这就是它。如果我们编写了自定义
tp_alloc
或tp_free
个插槽,我们需要修改它们以进行循环垃圾收集。大多数扩展程序将使用自动提供的版本。
不幸的是,一个不清楚你自己不需要这样做的地方是Supporting Cyclic Garbage Collection documentation。
<强>详情:强>
使用Noddy_new
中tp_new
个TypeObject
个插槽中的tp_alloc
函数分配Noddy。根据{{3}},“新”函数应该做的主要事情是调用the documentation。您通常不会自己编写PyType_GenericAlloc()
,而是默认为PyType_IS_GC(type)
。
查看tp_alloc
slot会根据_PyObject_GC_Malloc
显示更改的部分。首先,它调用PyObject_Malloc
而不是_PyObject_GC_TRACK(obj)
,然后调用PyObject_New
。 [请注意,PyObject_Malloc
真正做的就是致电tp_init
,然后致电Py_TPFLAGS_HAVE_GC
。]
同样,在重新分配时,您调用PyType_GenericAlloc()
in the Python source,对PyObject_GC_Del
的类自动设置为tp_free
slot。 PyObject_GC_UnTrack
包含与package workspace;
public class Fencing {
public static void main(String[] args) {
boolean b = true;
double corner = 0;
double center = 0;
double side = 0;
int i = 0;
int j = 0;
int[][] map = {
{ 0, 1, 1, 0 },
{ 1, 1, 1, 1 },
{ 1, 1, 1, 1 },
{ 1, 1, 0, 1 }
};
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
if (map[i][j] != 1 && map[i][j] != 0) {
b = false;
System.out.println("--> A value of " + map[i][j] + " was found at " + i + "," + j);
}
}
}
if (b == false && i == 3) {
System.out.println("The map is invalid");
return;
} else {
System.out.println("Map is valid");
}
if (map[0][0] == 1) {
corner += 5;
if (map[1][0] == 1 && map[0][1] == 1) {
corner += 0;
}
if (map[1][0] != 1 && map[0][1] != 1) {
corner += 5;
}
if (map[1][0] != 1 && map[0][1] == 1 || map[1][0] == 1 && map[0][1] != 1) {
corner += 2.5;
}
} else {
corner += 0;
}
if (map[0][3] == 1) {
corner += 5;
if (map[1][3] == 1 && map[0][2] == 1) {
corner += 0;
}
if (map[1][3] != 1 && map[0][2] != 1) {
corner += 5;
}
if (map[1][3] != 1 && map[0][2] == 1 || map[1][3] == 1 && map[0][2] != 1) {
corner += 2.5;
}
} else {
corner += 0;
}
if (map[3][0] == 1) {
corner += 5;
if (map[3][1] == 1 && map[2][0] == 1) {
corner += 0;
}
if (map[3][1] != 1 && map[02][0] != 1) {
corner += 5;
}
if (map[3][1] != 1 && map[2][0] == 1 || map[3][1] == 1 && map[2][0] != 1) {
corner += 2.5;
}
} else {
corner += 0;
}
if (map[3][3] == 1) {
corner += 5;
if (map[3][2] == 1 && map[2][3] == 1) {
corner += 0;
}
if (map[3][2] != 1 && map[2][3] != 1) {
corner += 5;
}
if (map[3][2] != 1 && map[2][3] == 1 || map[3][2] == 1 && map[2][3] != 1) {
corner += 2.5;
}
} else {
corner += 0;
}
System.out.println("Corner fencing = " + corner);
i = 0;
j = 0;
for (j = 1; j < 3; j++) { // Top
if (map[0][j] == 1) {
side += 2.5;
if (map[0][j + 1] == 1 && map[0][j - 1] == 1) {
side += 0;
}
if (map[0][j + 1] != 1 || map[0][j - 1] != 1) {
side += 2.5;
}
if (map[0][j + 1] != 1 && map[0][j - 1] != 1) {
side += 5;
}
} else {
side += 0;
}
}
System.out.println("After the first row, fencing = " + side);
i = 0;
j = 0;
for (j = 1; j < 3; j++) { // Bottom
if (map[3][j] == 1) {
side += 2.5;
if (map[3][j + 1] == 1 && map[3][j - 1] == 1) {
side += 0;
}
if (map[3][j + 1] != 1 || map[3][j - 1] != 1) {
side += 2.5;
}
if (map[3][j + 1] != 1 && map[3][j - 1] != 1) {
side += 5;
}
} else {
side += 0;
}
}
System.out.println("After the bottom row, fencing = " + side);
i = 0;
j = 0;
for (i = 1; i < 3; i++) {// Right
if (map[i][3] == 1) {
side += 2.5;
if (map[i + 1][3] == 1 && map[i - 1][3] == 1) {
side += 0;
}
if (map[i + 1][3] != 1 || map[i - 1][3] != 1) {
side += 2.5;
}
if (map[i + 1][3] != 1 && map[i - 1][3] != 1) {
side += 5;
}
} else {
side += 0;
}
}
System.out.println("After the first column, fencing = " + side);
i = 0;
j = 0;
for (i = 1; i < 3; i++) {// Left
if (map[i][0] == 1) {
side += 2.5;
if (map[i + 1][0] == 1 && map[i - 1][0] == 1) {
side += 0;
}
if (map[i + 1][0] != 1 || map[i - 1][0] != 1) {
side += 2.5;
}
if (map[i + 1][0] != 1 && map[i - 1][0] != 1) {
side += 5;
}
} else {
side += 0;
}
}
System.out.println("After the last column, fencing = " + side);
}
}
相同的代码,因此无需调用untrack。