2011-03-23 69 views
1

我已经编写了一个守护程序来监视目录中的文件,并在任何文件发生更改时发送电子邮件。我使用bb-freeze将其编译为Windows .exe。让我们在运行了几天后注意到它在内存中占用的空间越来越大。Python smtplib模块泄漏内存

我用Heapy来监视.py文件中的内存使用情况(不是编译后的.exe),发现每次调用函数时,对象的数量都增加了3,相应的内存使用增加了484字节。它使用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='[email protected]', username='[email protected]', 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) 

我刚刚在互联网上的某个地方看到了这段代码并复制了它。它可以工作,但会泄漏内存。 有人可以帮我找出内存泄漏发生的地方吗? :(

编辑:似乎使用msg.as_string()是什么导致内存泄漏。使用纯文本如msg =“Blah”代替msg.as_string()修复了这个问题。不允许我添加主题行

+1

你应该在这里添加你的答案作为答案并接受它,而不是编辑你的帖子。或者,如果其中一个答案在这里最终准确地反映了答案,您应该接受它。 :) – sarnold 2011-03-24 04:55:08

回答

0

你有一个使用的Python Debugger

编辑查找内存泄漏一个伟大的工具,您也可以尝试Valgrind访问:?。

对不起,只是注意到你说你在Windows上,哪个valgrind不能用于:(。

无论如何,您可能希望查看Windows的Python用于加密的任何库。在我的Mac上,您提供的脚本显示围绕mailServer.starttls()调用的内存泄漏,并且罪魁祸首看起来是围绕libssl/libcrypto的python包装。对不起,如果这没有帮助(非窗户...)。

1

我敢打赌,你有一个参考周期。

编辑:我改变你的代码稍微:

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

def sendMail(subject, text): 
    gmailUser = '[email protected]' 
    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) 

孔雀鱼没有为Python和C++编译器,我的版本的工作,所以我不能测试输出(也许这是行不通的你呢?)。我可以告诉你的是,我在进程浏览器中观察了垃圾收集输出和一些内存统计信息,发现该代码中没有明显的差异或泄漏问题。关键更改:删除了对SMTP.ehlo()(不必要的)的调用,删除了默认的函数参数(我怀疑这些参数可能保留在对象中,只要函数在范围内,这些对象可以保持SMTP周围的物体)。所以你可能想尝试一个,然后看看哪个修复了你的问题。

查看this post获取帮助和一些工具。

0

1)你可以尝试用简单的字符串文本做消息来做同样的代码。
2)您可以删除对ehlo的调用,并查看内存泄漏是否由此修复。 (他们是不必要的)

import smtplib 


def main() : 
    fromaddr = '[email protected]' 
    toaddrs = '[email protected]' 
    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()