Dowser: “内部函数的错误参数”
我正在尝试使用Dowser,这个工具真的很酷,但我遇到了一点小问题,谷歌上找不到有用的信息,所以我来这里求助了.. ^^;
我在运行一个CherryPy和SQLAlchemy的应用程序.. 一切正常,除了当我启用Dowser(也就是调用dowser.Root()之后),偶尔会出现一些错误,比如:
系统错误: ../Objects/tupleobject.c:809: 内部函数的参数有问题
这个错误出现在一些看起来很简单的操作上,比如访问一个SQLA映射的字段.. 相关的错误追踪信息如下:
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/attributes.py", line 158, in __get__
return self.impl.get(instance_state(instance), instance_dict(instance))
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/attributes.py", line 377, in get
value = callable_()
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/strategies.py", line 586, in __call__
result = q.all()
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/query.py", line 1267, in all
return list(self)
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/query.py", line 1422, in instances
rows = [process[0](context, row) for row in fetch]
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/query.py", line 2032, in main
return _instance(row, None)
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/mapper.py", line 1653, in _instance
identitykey = identity_key(row)
File "/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/mapper.py", line 1594, in identity_key
return (identity_class, tuple(row[column] for column in pk_cols))
这可能和Dowser的线程有关,它在访问垃圾回收器吗?你们有什么建议我可以检查的地方吗?
我在Xubuntu Jaunty上运行Python 2.6.2。
谢谢大家的关注!
1 个回答
摘要
在我的例子中是 Dozer,而不是 Dowser,但基本上是同样的事情——在一个单独的线程中循环遍历 gc.get_objects
并统计类型。还可以选择互动地追踪所选对象的引用者和被引用者。
正如我在评论中提到的,这个错误仍然会发生。在使用 SQLAlchemy 时,我遇到了两次 SystemError: ../Objects/tupleobject.c:892: bad argument to internal function
的堆栈跟踪错误,这个错误是在元组推导中出现的(一个, 二)。这里有一个合理的解释。
解释
如果我查看 CPython 的 tupleobject.c
源码 第892行,在这个函数之前有一个显著的注释:
以下函数打破了元组不可变的概念:它改变了元组的大小。只有当只有一个模块引用这个对象时,我们才能做到这一点。你也可以把它看作是创建一个新的元组对象并销毁旧的,只是更高效而已。无论如何,如果这个元组可能已经被代码的其他部分知道,就不要使用这个。
假设:
- 当 SQLAlchemy 在主线程中构建复杂的元组推导时,
- Dozer 从另一个线程获取了对“正在进行”的元组的引用,
- 并打破了
_PyTuple_Resize
的假设(即非空元组只有一个引用者)
if (v == NULL || Py_TYPE(v) != &PyTuple_Type ||
(Py_SIZE(v) != 0 && Py_REFCNT(v) != 1)) {
*pv = 0;
Py_XDECREF(v);
PyErr_BadInternalCall(); // line 892
return -1;
}
总结
Dozer 是一个很棒的实时内存检查工具,但它有一个局限性,就是被检查的应用程序在使用 Dozer 的情况下可能无法长时间运行(例如,能运行几个小时)。因此,更实际的做法是等到内存泄漏显现出来后,再 实时连接 Dozer 到进程中。