Frage

Ich versuche, ein einfaches Python -Skript für mein Mobiltelefon zu schreiben, um eine Webseite regelmäßig mit URRLIB2 zu laden. Tatsächlich kümmere ich mich nicht wirklich um die Serverantwort, sondern ich möchte nur einige Werte in der URL an den PHP weitergeben. Das Problem ist, dass Python für S60 den alten 2.5.4 Python -Kern verwendet, der im URRLIB2 -Modul ein Speicherleck zu haben scheint. Wie ich las, scheint es auch in jeder Art von Netzwerkkommunikation solche Probleme zu geben. Dieser Fehler wurde gemeldet hier Vor ein paar Jahren, während auch einige Problemumgehungen veröffentlicht wurden. Ich habe alles ausprobiert, was ich auf dieser Seite finden konnte, und mit Hilfe von Google, aber mein Telefon hat nach ~ 70 Seitenladungen immer noch kein Speicher mehr. Seltsamerweise scheint der Garbege -Sammler keinen Unterschied zu machen, außer dass mein Drehbuch viel langsamer ist. Es wird gesagt, dass der neuere (3.1) Kern dieses Problem löst, aber leider kann ich ein Jahr (oder mehr) auf den kommenden S60 -Port kaum erwarten.

So sucht mein Skript, wie ich jeden kleinen Trick hinzugefügt habe, den ich gefunden habe:


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()
Irgendwelche Vorschläge, wie kann es für immer funktionieren, ohne den Fehler "Speicher nicht zuweisen"? Danke für den Vormarsch, Prost, B_M

aktualisieren:Ich habe es geschafft, 92 Mal eine Verbindung herzustellen, bevor es keinen Gedächtnis mehr hat, aber es ist immer noch nicht gut genug.

Update2:Versuchte die Socket -Methode wie zuvor vorgeschlagen, dies ist die zweitbeste (falsche) Lösung bisher:


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)
Ich habe die kleinen Tricks auch von oben ausprobiert. Der Thread schließt nach ~ 50 Uploads (das Telefon hat 50 MB Speicher übrig, offensichtlich hat die Python -Shell nicht.)

AKTUALISIEREN: Ich glaube, ich komme der Lösung näher! Ich habe versucht, mehrere Daten zu senden, ohne den Socket zu schließen und wieder zu öffnen. Dies kann der Schlüssel sein, da diese Methode nur einen offenen Dateideskriptor hinterlässt. Das Problem ist:


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...
*: Fehlermeldung: 10053, Software verursachte Verbindungsabbruch

Warum kann ich nicht mehrere Nachrichten senden?

War es hilfreich?

Lösung

Ich finde Dies ist wahrscheinlich dein Problem. Um diesen Thread zusammenzufassen, gibt es ein Speicherleck in der DNS -Suche von Pys60, und Sie können ihn umgehen, indem Sie DNS -Lookup außerhalb der inneren Schleife bewegen.

Andere Tipps

Mit dem von Ihrem Link vorgeschlagenen Testcode habe ich meine Python -Installation getestet und bestätigt, dass er tatsächlich ausgelöst wird. Aber wenn ich, wie @russell vorschlug, ich jeweils lege urlopen in seinem eigenen Prozess das Betriebssystem sollte Reinigen Sie die Speicherlecks. In meinen Tests bleiben Speicher, nicht erreichbare Objekte und geöffnete Dateien mehr oder weniger konstant. Ich habe den Code in zwei Dateien geteilt:

Connection.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()

Dies ist natürlich sequentiell, sodass Sie jeweils nur eine einzelne Verbindung ausführen, was möglicherweise ein Problem für Sie ist oder nicht. Wenn dies der Fall ist, müssen Sie eine nicht blockierende Art der Kommunikation mit den Prozessen finden, die Sie auf den Markt bringen, aber ich werde das als Übung für Sie verlassen.

BEARBEITEN: Beim erneuten Lesen Ihrer Frage scheinen Sie sich nicht um die Serverantwort interessieren. In diesem Fall können Sie den gesamten Code für ein wickelbezogenes Code loswerden. Und offensichtlich werden Sie das nicht haben print_unreachable_len() Auch verwandte Bits in Ihrem endgültigen Code.

In urllib2, der in urllib2.py:1216 erstellt wurde, gibt es einen Referenzzyklus. Das Problem geht und existiert seit 2009.https://bugs.python.org/issue1208304

Dies scheint eine (sehr!) Hacky -Problemumgehung zu sein, aber ein bisschen Googeln gefunden Dieser Kommentar Zu dem Problem:

Anscheinend hinzufügen f.read(1) Wird das Lachen stoppen!

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

BEARBEITEN: Oh, ich sehe, du hast schon f.read(1)... dann habe ich alle aus den Ideen heraus:/

Erwägen Sie, die niedrige Ebene zu verwenden Sockel -API (verbunden wie man) anstelle von urllib2.

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)

Wie man eine HTTP-Anfrage über Low-Level-Sockets ausführt und liest, ist ein bisschen über den Rahmen der Frage hinaus (und kann vielleicht selbst eine gute Frage auf Stackoverflow stellen-ich habe sie gesucht, aber nicht gesehen), aber ich hoffe das zeigt Sie in Richtung einer Lösung, die Ihr Problem beheben kann!

bearbeiten Eine Antwort hier über die Verwendung makefile kann hilfreich sein: HTTP -Grundauthentifizierung mit Sockets in Python

Dies läuft für mich nicht mit Python 2.6.1 auf einem Mac. Welche Version verwenden Sie?

Übrigens funktioniert Ihr Programm aufgrund einiger Tippfehler nicht. Hier ist eine, die funktioniert:

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

Abhängig von der Plattform und der Python -Version veröffentlicht Python möglicherweise nicht den Speicher an das Betriebssystem. Sieh dir das an Stackoverflow -Thread. Trotzdem sollte Python nicht endlos Gedächtnis konsumieren. Nach dem von Ihnen verwendeten Code zu urteilen, scheint er in der Python -Laufzeit Fehler zu sein wenn nicht, Urllib/Sockets verwenden Globale, von denen ich nicht glaube, dass sie Python auf S60 verantwortlich machen!

Haben Sie andere Quellen für Speicherleckage in Betracht gezogen? Endlose Protokolldatei öffnen, immer so ein Array oder so ein so starkes? Wenn es sich wirklich um einen Fehler in der Schnittstelle zwischen Sockets handelt, besteht die einzige Möglichkeit, den Subprozess -Ansatz zu verwenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top