如何确定Python 2.7.5中的实习字符串数?

jch*_*chl 11 python string string-interning

在早期版本的Python中(我不记得哪个),gc.get_referrers可以使用对任意实习字符串的调用来获取对interneddict 的引用,然后可以查询其长度.

但是这不再适用于Python 2.7.5:gc.get_referrers(...)不再包含interned它返回的列表中的dict.

在Python 2.7.5中,有没有其他方法来确定实习字符串的数量?如果是这样,怎么样?

use*_*ica 3

您可以这样做,但所有选项都很混乱,并且充满了几乎无用的警告,所以首先,让我们考虑一下您是否真的想要这样做。

驻留字符串并不会延长其生命周期。您不必担心 interned dict 会永远增长,充满您不需要的字符串。因此,字符串驻留不太可能是一个实际的内存问题,并且了解有多少字符串已被驻留可能毫无用处。

如果您仍然想这样做,让我们看看您的选择。


正确的方法可能是使用您自己的实习实现...除了 Python 乏善可陈的弱引用支持不允许您创建对字符串的弱引用。这意味着,如果您尝试这种方法,您要么传递自己的弱引用字符串包装器,要么让内部字符串永远保持活动状态。这两种选择都很糟糕。


实际上有一个函数可以打印您所询问的信息......但它也可以取消所有内容。它的存在是一个实现细节,并且只能通过 C API 访问,因此我们需要使用ctypes.pythonapi来获取它。

import ctypes

_Py_ReleaseInternedStrings = ctypes.pythonapi._Py_ReleaseInternedStrings

_Py_ReleaseInternedStrings.argtypes = ()
_Py_ReleaseInternedStrings.restype = None

_Py_ReleaseInternedStrings()
Run Code Online (Sandbox Code Playgroud)

输出:

releasing 3461 interned strings
total size of all interned strings: 33685/0 mortal/immortal
Run Code Online (Sandbox Code Playgroud)

列出的总大小是字符串长度的总和,因此它们不包括对象标头或空终止符。


您可能不高兴每次想要检查有多少字符串时都必须释放所有保留字符串。不幸的是,Python 不会公开 interned 字典,即使是通过 C API 或 GC hooks 也是如此。你还能尝试什么?好吧,转向更疯狂的选项,那就是调试器。

ecatmur 发布了一个疯狂的 hack,以无人值守模式启动 GDB 进程,并使用条件断点来获取,这是一个与您想要访问的字典errnomap非常相似的字典。interned这可以修改为访问interned字典。它将非常不便携并且极难维护。


启动调试器也是一个糟糕的选择。你还能尝试什么?好吧,您始终可以构建自己的自定义 Python 版本。从python.org下载源码,添加

PyObject *
AwfulHackToGetTheInternedDict(void)
{
    if (interned == NULL) {
        // No interned dict yet.
        Py_RETURN_NONE;
    }
    Py_INCREF(interned);
    return interned;
}
Run Code Online (Sandbox Code Playgroud)

、构建Objects/stringobject.c和安装。您可能需要使用 virtualenv 来将其与普通的 Python 解释器分开。有了这个可怕的黑客,你可以做

import ctypes

AwfulHackToGetTheInternedDict = ctypes.pythonapi.AwfulHackToGetTheInternedDict

AwfulHackToGetTheInternedDict.argtypes = ()
AwfulHackToGetTheInternedDict.restype = ctypes.py_object

interned = AwfulHackToGetTheInternedDict()
Run Code Online (Sandbox Code Playgroud)

获取所有内部字符串的字典。


所以,这些是你的选择,或者至少是我想到的选择。我还尝试强制 GC 跟踪字符串,然后对其进行驻留以使驻留的字典通过 GC 可见,但是调用PyObject_GC_Track字符串会导致致命错误,因此这不起作用。