8

携帯電話用の簡単なPythonスクリプトを作成して、urrlib2を使用してWebページを定期的にロードしようとしています。実際、私はサーバーの応答についてはあまり気にしません。URLのいくつかの値をPHPに渡したいだけです。問題は、Python forS60が古い2.5.4Pythonコアを使用していることです。これは、urrlib2モジュールでメモリリークが発生しているようです。私が読んだように、あらゆるタイプのネットワーク通信にもそのような問題があるようです。このバグはここで報告されています数年前、いくつかの回避策も投稿されました。そのページで見つけたすべてのことをGoogleの助けを借りて試しましたが、約70ページの読み込み後も携帯電話のメモリが不足しています。不思議なことに、Garbege Collectorは、スクリプトを大幅に遅くすることを除いて、何の違いももたらさないようです。新しい(3.1)コアがこの問題を解決すると言われていますが、残念ながら、S60ポートが来るのを1年(またはそれ以上)待つことはできません。

私が見つけたすべての小さなトリックを追加した後の私のスクリプトは次のようになります。


import urrlib2, httplib, gc
while(true):
 url = "http://something.com/foo.php?parameter=" + value 
 f = urllib2.urlopen(url)
 f.read(1)
 f.fp._sock.recv=None # hacky avoidance
 f.close()
 del f
 gc.collect()
「メモリを割り当てることができません」というエラーが発生せずに永久に機能させる方法についての提案はありますか?よろしくお願いします、乾杯、b_m

更新: メモリがなくなる前に92回接続できましたが、それでも十分ではありません。

update2: 前に提案したようにソケットメソッドを試しました。これはこれまでのところ2番目に良い(間違った)解決策です:


class UpdateSocketThread(threading.Thread):
  def run(self):
  global data
  while 1:
  url = "/foo.php?parameter=%d"%data
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect(('something.com', 80))
  s.send('GET '+url+' HTTP/1.0\r\n\r\n')
  s.close()
  sleep(1)
上からもちょっとしたコツを試してみました。スレッドは最大50回のアップロード後に閉じます(電話には50MBのメモリが残っていますが、明らかにPythonシェルにはありません)。

更新:私は解決策に近づいていると思います!ソケットを閉じたり開いたりせずに複数のデータを送信してみました。この方法では開いているファイル記述子が1つだけ残るため、これが重要な場合があります。問題は:


import socket
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect(("something.com", 80))
socket.send("test") #returns 4 (sent bytes, which is cool)
socket.send("test") #4
socket.send("test") #4
socket.send("GET /foo.php?parameter=bar HTTP/1.0\r\n\r\n") #returns the number of sent bytes, ok
socket.send("GET /foo.php?parameter=bar HTTP/1.0\r\n\r\n") #returns 0 on the phone, error on Windows7*
socket.send("GET /foo.php?parameter=bar HTTP/1.0\r\n\r\n") #returns 0 on the phone, error on Windows7*
socket.send("test") #returns 0, strange...
*:エラーメッセージ:10053、ソフトウェアにより接続が中止されました

複数のメッセージを送信できないのはなぜですか?

4

7 に答える 7

1

リンクで提案されたテスト コードを使用して、Python のインストールをテストし、実際にリークすることを確認しました。しかし、@Russellが示唆したように、それぞれurlopenを独自のプロセスに入れると、OSはメモリリークをクリーンアップするはずです。私のテストでは、メモリ、到達不能オブジェクト、開いているファイルはすべてほぼ一定のままです。コードを 2 つのファイルに分割します。

接続.py

import cPickle, urllib2

def connectFunction(queryString):
    conn = urllib2.urlopen('http://something.com/foo.php?parameter='+str(queryString))
    data = conn.read()
    outfile = ('sometempfile'. 'wb')
    cPickle.dump(data, outfile)
    outfile.close()

if __name__ == '__main__':
    connectFunction(sys.argv[1])

###launcher.py
import subprocess, cPickle

#code from your link to check the number of unreachable objects

def print_unreachable_len():
    # check memory on memory leaks
    import gc
    gc.set_debug(gc.DEBUG_SAVEALL)
    gc.collect()
    unreachableL = []

    for it in gc.garbage:
        unreachableL.append(it)
    return len(str(unreachableL))

    #my code
    if __name__ == '__main__':        
        print 'Before running a single process:', print_unreachable_len()
        return_value_list = []
        for i, value in enumerate(values): #where values is a list or a generator containing (or yielding) the parameters to pass to the URL
             subprocess.call(['python', 'connection.py', str(value)])
             print 'after running', i, 'processes:', print_unreachable_len()
             infile = open('sometempfile', 'rb')
             return_value_list.append(cPickle.load(infile))
             infile.close()

明らかに、これはシーケンシャルであるため、一度に 1 つの接続のみを実行しますが、これは問題になる場合とそうでない場合があります。そうである場合は、起動しているプロセスと通信するためのノンブロッキングの方法を見つける必要がありますが、それは演習として残しておきます。

編集:あなたの質問を読み直すと、サーバーの応答を気にしていないようです。その場合、酸洗いに関連するすべてのコードを取り除くことができます。print_unreachable_len()そして明らかに、最終的なコードにも関連するビットはありません。

于 2010-11-19T16:06:57.603 に答える
0

urllib2の代わりに低レベルのソケット API (関連するhowto ) を使用することを検討してください。

HOST = 'daring.cwi.nl'    # The remote host
PORT = 50007              # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send('GET /path/to/file/index.html HTTP/1.0\n\n')

 # you'll need to figure out how much data to read and read that exactly
 # or wait for read() to return data of zero length (I think!)
DATA_SZ = 1024
data    = s.recv(DATA_SZ)
s.close()
print 'Received', repr(data)

低レベルのソケットを介して HTTP リクエストを実行および読み取る方法は、質問の範囲を少し超えています (おそらく、stackoverflow でそれ自体で良い質問になるかもしれません — 検索しましたが、表示されませんでした)。問題を解決する可能性のあるソリューションの方向性を示します!

編集ここでの使用に関する回答makefileが役立つ場合があります: Python でソケットを使用した HTTP 基本認証

于 2010-11-19T14:57:23.603 に答える
0

これは、Mac 上の Python 2.6.1 では漏れません。どのバージョンを使用していますか?

ところで、いくつかのタイプミスが原因でプログラムが機能しません。動作するものは次のとおりです。

import urllib2, httplib, gc
value = "foo"
count = 0
while(True):
    url = "http://192.168.1.1/?parameter=" + value 
    f = urllib2.urlopen(url)
    f.read(1)
    f.fp._sock.recv=None # hacky avoidance
    f.close()
    del f
    print "count=",count
    count += 1
于 2010-11-21T13:07:38.567 に答える
0

プラットフォームと Python のバージョンによっては、Python が OS にメモリを解放しない場合があります。このスタックオーバーフロー スレッドを参照してください。とはいえ、python は際限なくメモリを消費するべきではありません。あなたが使用しているコードから判断すると、urllib/sockets がグローバルを使用していない限り、Python ランタイムのバグのようです。S60 の Python のせいです!

メモリリークの他の原因を考慮しましたか? 無限のログ ファイルが開いていて、配列が増え続けている、またはそのようなものはありませんか? 本当にソケット インターフェイスのバグである場合は、サブプロセス アプローチを使用するしかありません。

于 2010-11-22T12:50:17.947 に答える
0

これはおそらくあなたの問題だと思います。そのスレッドを要約すると、Pys60 の DNS ルックアップにメモリ リークがあり、DNS ルックアップを内側のループの外に移動することで回避できます。

于 2011-01-15T02:43:33.557 に答える
0

これは (非常に!) ハックな回避策のように思えますが、少しグーグルで調べてみると、この問題に関する次のコメントが見つかりました。

どうやら追加f.read(1)すると漏れが止まります!

import urllib2
f = urllib2.urlopen('http://www.google.com')
f.read(1)
f.close()

編集:ああ、私はあなたがすでに持っているように見えますf.read(1)...私はすべてアイデアがありません:/

于 2010-11-18T11:37:20.360 に答える