在 Python 的早期版本(我不记得是哪个版本)中,调用gc.get_referrers
任意内部字符串可用于获取对interned
dict 的引用,然后可以查询其长度。
但这在 Python 2.7.5 中不再有效:gc.get_referrers(...)
不再interned
在它返回的列表中包含 dict。
在 Python 2.7.5 中还有其他方法可以确定实习字符串的数量吗?如果是这样,怎么做?
在 Python 的早期版本(我不记得是哪个版本)中,调用gc.get_referrers
任意内部字符串可用于获取对interned
dict 的引用,然后可以查询其长度。
但这在 Python 2.7.5 中不再有效:gc.get_referrers(...)
不再interned
在它返回的列表中包含 dict。
在 Python 2.7.5 中还有其他方法可以确定实习字符串的数量吗?如果是这样,怎么做?
您可以这样做,但是所有选项都很混乱,并且充满了几乎无用的警告,所以首先,让我们考虑一下您是否真的想要这样做。
实习字符串不会延长其生命周期。您不必担心实习生的 dict 会永远增长,其中充满了您不需要的字符串。因此,字符串实习不太可能是一个实际的内存问题,并且了解有多少字符串已被实习可能毫无用处。
如果你仍然想这样做,让我们来看看你的选择。
正确的方法可能是使用您自己的实习实现...除了 Python 乏善可陈的弱引用支持不允许您创建对字符串的弱引用。这意味着如果你尝试这种方法,你要么被困在传递你自己的弱引用字符串包装器,要么让被留存的字符串永远保持活动状态。这两种选择都很糟糕。
实际上有一个功能可以打印您要询问的信息……但它也取消了所有内容。它的存在是一个实现细节,它只能通过 C API 访问,所以我们需要使用ctypes.pythonapi
它来了解它。
import ctypes
_Py_ReleaseInternedStrings = ctypes.pythonapi._Py_ReleaseInternedStrings
_Py_ReleaseInternedStrings.argtypes = ()
_Py_ReleaseInternedStrings.restype = None
_Py_ReleaseInternedStrings()
输出:
releasing 3461 interned strings
total size of all interned strings: 33685/0 mortal/immortal
列出的总大小是字符串长度的总和,因此它们不包括对象标头或空终止符。
您可能不满意每次您想检查有多少时都必须释放所有的实习字符串。不幸的是,Python 没有公开实习字典,即使是通过 C API 或通过 GC 挂钩。你还能尝试什么?好吧,继续更疯狂的选择,有调试器。
ecatmur 发布了一个疯狂的 hack,以无人值守模式启动 GDB 进程,并使用条件断点来获取,与您要访问errnomap
的 dict 非常相似的 dict 。interned
这可以改为访问interned
字典。这将是高度不可移植且极难维护的。
启动调试器也是一个糟糕的选择。你还能尝试什么?好吧,您总是可以构建自己的 Python 自定义构建。从python.org下载源代码,添加
PyObject *
AwfulHackToGetTheInternedDict(void)
{
if (interned == NULL) {
// No interned dict yet.
Py_RETURN_NONE;
}
Py_INCREF(interned);
return interned;
}
,Objects/stringobject.c
构建和安装。您可能希望使用 virtualenv 将其与普通的 Python 解释器分开。有了这个可怕的黑客,你可以做
import ctypes
AwfulHackToGetTheInternedDict = ctypes.pythonapi.AwfulHackToGetTheInternedDict
AwfulHackToGetTheInternedDict.argtypes = ()
AwfulHackToGetTheInternedDict.restype = ctypes.py_object
interned = AwfulHackToGetTheInternedDict()
获取所有实习字符串的字典。
所以,这些是你的选择,或者至少是我想到的选择。我还尝试强制 GC 跟踪一个字符串,然后将其实习以使实习的 dict 通过 GC 可见,但调用PyObject_GC_Track
一个字符串会导致致命错误,所以这不起作用。
出于您的目的,我认为真正的答案是使用更强大的内存分析解决方案。
有几个选项可以做到这一点,例如 pypi 上的 free memory_profiler选项。