简体   繁体   English

Python smtplib模块泄漏内存

[英]Python smtplib module leaks memory

I have written a daemon of sorts to monitor files in a directory and send out an email whenever there is a change in any of the files. 我编写了各种守护程序来监视目录中的文件,并在任何文件发生更改时发送电子邮件。 I used bb-freeze to compile it to a Windows .exe. 我使用bb-freeze将其编译为Windows .exe。 I noticed after letting it run for a couple of days that it was taking more and more space in memory. 在运行了几天后,我注意到它占用了越来越多的内存空间。

I used Heapy to monitor the memory usage in the .py file (not the compiled .exe) and found out that for each call to the function, the number of objects was increasing by 3 with a corresponding memory usage increase of 484 Bytes. 我使用Heapy监视.py文件(而不是已编译的.exe)中的内存使用情况,发现对于该函数的每次调用,对象数量都增加了3个,相应的内存使用量增加了484字节。 It uses the smtplib module and I cannot understand where the leak is happening. 它使用smtplib模块,我不知道泄漏发生在哪里。

from guppy import hpy
import time
import gc

import os
import smtplib
import mimetypes
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEAudio import MIMEAudio
from email.MIMEImage import MIMEImage
from email.Encoders import encode_base64

def sendMail(subject, text, to='blah@gmail.com', username='more.blah@gmail.com', password='blah', smtpServer='smtp.gmail.com', smtpPort=587):
   gmailUser = username
   gmailPass = password
   recipient = to

   msg = MIMEMultipart()
   msg['From'] = gmailUser
   msg['To'] = recipient
   msg['Subject'] = subject
   msg.attach(MIMEText(text))

   mailServer = smtplib.SMTP(smtpServer, smtpPort)
   mailServer.ehlo()
   mailServer.starttls()
   mailServer.ehlo()
   mailServer.login(gmailUser, gmailPass)
   mailServer.sendmail(gmailUser, recipient, msg.as_string())
   mailServer.quit()

   print('Sent email to "%s"' % recipient)

if __name__=='__main__':
   while True:
      sendMail("Function", "Blah!")
      gc.collect()
      print hpy().heap()
      time.sleep(10)

I just saw this code somewhere on the internet and copied it. 我只是在互联网上的某个地方看到了此代码并将其复制。 It works but leaks memory. 它可以工作,但会泄漏内存。 Can someone help me find out where the memory leak is happening?? 有人可以帮我找出发生内存泄漏的地方吗? :( :(

EDIT: Seems like using msg.as_string() is what is causing the memory leak. 编辑:好像使用msg.as_string()是导致内存泄漏的原因。 Using a plain text such as msg="Blah" in place of msg.as_string() fixes the issue. 使用纯文本(例如msg =“ Blah”)代替msg.as_string()可解决此问题。 But that does not allow me to add a subject line. 但这不允许我添加主题行。

I would bet that you have a reference cycle. 我敢打赌,您有一个参考周期。

Edit: I altered your code slightly to: 编辑:我将您的代码稍作更改为:

import time
import gc
import smtplib
import mimetypes
from email.MIMEText import MIMEText

def sendMail(subject, text):
   gmailUser = 'myemail@gmail.com'
   gmailPass = 'mypassword'
   recipient = gmailUser

   msg = MIMEMultipart()
   msg['From'] = gmailUser
   msg['To'] = recipient
   msg['Subject'] = subject
   msg.attach(MIMEText(text))

   mailServer = smtplib.SMTP('smtp.gmail.com', 587)
   mailServer.starttls()
   mailServer.login(gmailUser, gmailPass)
   mailServer.sendmail(gmailUser, recipient, msg.as_string())
   mailServer.quit()

   print('Sent email to "%s"' % recipient)

if __name__=='__main__':
   gc.set_debug(gc.DEBUG_LEAK)
   for item in range(1000):
      sendMail("Function", "Blah!")
      gc.collect()
      time.sleep(2)

Guppy does not work for the version of python and c++ compiler I have, so I couldn't test that output (maybe it doesn't work for you either?). Guppy对我拥有的python和c ++编译器版本不起作用,因此我无法测试该输出(也许对您也不起作用?)。 What I can tell you is that I watched the garbage collection output and some memory statistics in process explorer and found no significant variance or issues with a leak in that code. 我可以告诉您的是,我在流程浏览器中观察了垃圾回收输出和一些内存统计信息,发现该代码中没有明显的差异或泄漏问题。 Key changes: removed calls to SMTP.ehlo() (unnecessary), removed default function parameters (I suspected these might stay around as objects that could be referred to as long as long as the function was in scope, which might somehow keep the SMTP objects around). 关键更改:删除了对SMTP.ehlo()的调用(不必要),删除了默认函数参数(我怀疑只要函数处于作用域之内,它们就可能一直作为对象被引用,这可能会保留SMTP周围的物体)。 So you might want to try one then the other and see which fixes your problem. 因此,您可能要尝试一个然后另一个,然后看看哪个可以解决您的问题。

Check out this post for assistance and some tools. 查看这篇文章以获得帮助和一些工具。

Do you have access to Valgrind ? 您可以使用Valgrind吗? That is a great tool for finding memory leaks. 那是查找内存泄漏的好工具。 You could also try using the Python Debugger . 您也可以尝试使用Python Debugger

EDIT: 编辑:

Sorry, just noticed you said you were on Windows, which valgrind is not available for :(. 抱歉,刚刚注意到您说您在Windows上,该valgrind不适用于:(。

Anyway, you might want to look into whatever library Python for Windows uses for crypto. 无论如何,您可能想研究Python for Windows用于加密的任何库。 On my Mac, the script you provided shows a memory leak around the mailServer.starttls() call, and the culprit looks to be the python wrapper around libssl/libcrypto. 在我的Mac上,您提供的脚本显示了mailServer.starttls()调用周围的内存泄漏,而罪魁祸首似乎是libssl / libcrypto周围的python包装器。 Sorry if this is no help at all (being non-windows...). 抱歉,这根本没有帮助(非Windows ...)。

1) You could try to do the same code with simple string text as message. 1)您可以尝试使用简单的字符串文本作为消息来执行相同的代码。
2) You could remove the calls to ehlo and see if the memory leak is fixed by this. 2)您可以删除对ehlo的调用,然后查看是否解决了内存泄漏问题。 (they are unnecessary) (它们是不必要的)

import smtplib


def main() :
    fromaddr = 'ph111@gmail.com'
    toaddrs  = 'ph222@gmail.com'
    msg = 'my simple message'
    username = 'ph111'
    password = 'mypassword'
    server = smtplib.SMTP('smtp.gmail.com:587')
    server.starttls()
    server.login(username,password)
    server.sendmail(fromaddr, toaddrs, msg)
    server.quit()

if __name__ == '__main__':
    main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM