Python IMAP 搜索,搜索结果耗尽所有内存

标签 python search imaplib

我正在尝试使用 imaplib 从 Python 中的特定地址获取所有自动回复电子邮件。数周以来一切正常,但现在每次我运行我的程序时,我的所有 RAM 都会被消耗(几 GB!)并且脚本最终会被 OOM killer 杀死。

这是我目前使用的代码:

M = imaplib.IMAP4_SSL('server')
M.LOGIN('user', 'pass')
M.SELECT()
date = (datetime.date.today() - datetime.timedelta(1)).strftime("%d-%b-%Y")
result, data = M.uid('search', None, '(SENTON %s HEADER FROM "auto@site.com" NOT SUBJECT "RE:")' % date)
...

我确定应该返回不到 100 封几千字节的电子邮件。这可能是怎么回事?或者有没有办法限制返回的电子邮件数量? 谢谢!

最佳答案

如果无法重现问题,就无法确定原因是什么(如果没有看到触发问题的完整程序,并且知道您正在使用的所有依赖项的版本,当然也不能)。

不过,这是我最好的猜测。多个版本的 Python 包含非常浪费内存的 imaplib 实现。该问题在 Windows 上尤为明显,但不限于该平台。

问题的核心是从套接字读取字符串时分配的方式,以及imaplib从套接字读取字符串的方式。

从套接字读取时,Python 首先分配一个足够大的缓冲区来处理应用程序请求的字节数。这听起来可能很合理,可能是 16 kB。然后将数据读入该缓冲区,并向下调整缓冲区大小以适应实际读取的字节数。

此操作的效率取决于平台重新分配实现的质量。调整缓冲区大小最终可能会将其移动到更合适的位置,较小的大小可以避免浪费大量内存。或者它可能只是将不再分配为该区域的一部分的内存的尾部标记为可重用(它甚至可以在实践中重用它)。或者它最终可能会浪费技术上未分配的内存。

想象一下,如果您必须读取几十 kB 的数据,并且数据一次从网络到达几十个字节,那么内存被浪费的累积影响。更糟糕的是,想象一下如果数据真的是涓涓细流,而您一次只能得到几个字节。或者,如果您正在阅读几百 kB 的非常“大”的响应。

浪费的内存量 - 由进程有效分配,但不能以任何有意义的方式使用 - 可能是巨大的。 100 kB 的数据,一次读取 5 个字节需要 20480 个缓冲区。如果每个缓冲区从 16 kB 开始并且不成功缩小,导致它们保持在 16 Kb,那么您已经分配了至少 320MB 的内存来容纳这 100 kB数据。

某些版本的 imaplib 通过引入多层缓冲和复制加剧了这个问题。一个非常旧的版本(希望不是您实际使用的版本)甚至一次读取 1 个字节(在上述情况下会导致 1.6GB 的内存使用)。

当然,这个问题通常不会出现在 Linux 上,因为 Linux 上的重新分配器并不是那么糟糕。在以前的 Python 版本(在最新的 2.x 版本之前)的不同点上,这个错误被“修复”了,所以我不希望这些天看到它出现。这并不能解释为什么您的程序在以这种方式失败之前可以正常运行一段时间。

但这是我最好的猜测。

关于Python IMAP 搜索,搜索结果耗尽所有内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7913741/

相关文章:

batch-file - 批处理脚本 - 在目录中的多个文件中查找和替换文本

python - 如何在 Python 3 中阅读电子邮件内容

python - 更改 seaborn 中因子图的标题

c++ - 推荐用于 gem 迷阵游戏的改进匹配查找算法?

performance - 为单个网站使用多个域名(优点和缺点)

python - 为什么我不能在 Python 中登录 imap 服务器两次

python - 撤消使用 imaplib 获取的电子邮件的 "marked as read"状态

python - 通过python从变量中按id查找html页面中的元素

python - numpy 中球坐标创建四元数

python - 使用 while 循环计算百分比的怪癖