2

ディレクトリ内のファイルを監視し、ファイルに変更があるたびに電子メールを送信するデーモンを作成しました。bb-freeze を使用して Windows .exe にコンパイルしました。数日間実行した後、メモリ内のスペースがますます多くなっていることに気付きました。

Heapyを使用して (コンパイルされた .exe ではなく) .py ファイルのメモリ使用量を監視したところ、関数を呼び出すたびに、オブジェクトの数が 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='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)

インターネットのどこかでこのコードを見て、それをコピーしました。動作しますが、メモリ リークが発生します。誰かがメモリリークが発生している場所を見つけるのを手伝ってもらえますか?? :(

編集: msg.as_string() の使用がメモリ リークの原因のようです。msg="Blah" などのプレーン テキストを msg.as_string() の代わりに使用すると、問題が修正されます。しかし、それでは件名を追加できません。

4

3 に答える 3

1

参照サイクルがあると思います。

編集:コードを次のように少し変更しました:

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 は、私が持っている Python および C++ コンパイラのバージョンでは動作しないため、その出力をテストできませんでした (もしかしたら、あなたにも動作しないのでしょうか?)。私が言えることは、プロセス エクスプローラーでガベージ コレクションの出力といくつかのメモリ統計を確認したところ、そのコードに重大な差異やリークの問題は見つからなかったということです。主な変更点: SMTP.ehlo() への呼び出しを削除 (不要)、デフォルトの関数パラメーターを削除 (関数がスコープ内にある限り、これらは参照可能なオブジェクトとして存在し続ける可能性があるのではないかと疑っていました。周囲の物体)。そのため、いずれかを試して、どれが問題を解決するかを確認することをお勧めします。

支援といくつかのツールについては、この投稿を確認してください。

于 2011-03-23T18:14:40.433 に答える
0

1)メッセージと同じ単純な文字列テキストを使用して同じコードを実行することができます。
2)ehloの呼び出しを削除して、これによってメモリリークが修正されるかどうかを確認できます。(不要です)

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()
于 2011-03-23T18:20:20.147 に答える
0

Valgrindにアクセスできますか? これは、メモリ リークを見つけるための優れたツールです。Python Debuggerを使用することもできます。

編集:

申し訳ありませんが、valgrind が利用できない Windows を使用していると言ったことに気付きました :(.

とにかく、Python for Windows が暗号化に使用するライブラリを調べることをお勧めします。私の Mac では、提供されたスクリプトは呼び出しの周りでメモリ リークを示してmailServer.starttls()おり、犯人は libssl/libcrypto の周りの python ラッパーのようです。これがまったく役に立たない場合は申し訳ありません(Windows以外の場合...)。

于 2011-03-23T17:52:32.637 に答える