我正在尝试为手机编写一个简单的Python脚本,以便使用urrlib2定期加载网页。实际上我并不关心服务器响应,我只想将URL中的一些值传递给PHP。问题是Python for S60使用旧的2.5.4 Python核心,它似乎在urrlib2模块中有内存泄漏。正如我所读到的,在每种类型的网络通信中似乎都存在这样的问题。几年前已经报告了这个错误here,同时也发布了一些解决方法。我已尝试在该页面上找到的所有内容,并且在Google的帮助下,但在加载约70页后,我的手机仍然耗尽内存。奇怪的是,Garbege Collector似乎也没有任何区别,只是让我的脚本慢得多。据说,较新的(3.1)核心解决了这个问题,但遗憾的是我不能等待一年(或更长时间)来接收S60端口。
这是我添加的每一个小技巧后我的脚本的样子:
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: 尝试前面提到的套接字方法,这是迄今为止第二个最好的(错误的)解决方案:
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 shell没有。)
更新: 我想我越来越接近解决方案了!我尝试发送多个数据而不关闭并重新打开套接字。这可能是关键,因为此方法只会留下一个打开的文件描述符。问题是:
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,软件导致连接中止
为什么我不能发送多条消息?
答案 0 :(得分:1)
使用链接建议的测试代码,我测试了我的Python安装并确认它确实泄漏了。但是,如果像@Russell建议的那样,我将每个urlopen
放在自己的进程中,那么操作系统应该清理内存泄漏。在我的测试中,内存,无法访问的对象和打开的文件都或多或少保持不变。我将代码分成两个文件:
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()
显然,这是顺序的,因此您一次只能执行一个连接,这对您来说可能是也可能不是问题。如果是,您将不得不找到一种与您正在启动的流程进行通信的非阻塞方式,但我会将其作为练习留给您。
编辑:在重新阅读您的问题时,您似乎并不关心服务器响应。在这种情况下,您可以摆脱所有与酸洗相关的代码。显然,您的最终代码中也不会有print_unreachable_len()
个相关位。
答案 1 :(得分:1)
在urllib2.py:1216中创建的urllib2中存在一个引用循环。这个问题正在发生,自2009年以来一直存在。 https://bugs.python.org/issue1208304
答案 2 :(得分:0)
这似乎是一个(非常!)hacky解决方法,但有一点谷歌搜索找到了this comment问题:
显然添加f.read(1)
将阻止泄漏!
import urllib2
f = urllib2.urlopen('http://www.google.com')
f.read(1)
f.close()
编辑:哦,我看到你已经f.read(1)
了......我完全没有想法了:/
答案 3 :(得分:0)
考虑使用低级socket API(相关howto)而不是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)
如何通过低级套接字执行和读取HTTP请求有点超出了问题的范围(也许可能在stackoverflow上自己提出一个很好的问题 - 我搜索但没有看到它),但是我希望这可以指出您可以解决问题的解决方案!
编辑此处有关使用makefile
的回答可能会有所帮助:HTTP basic authentication using sockets in python
答案 4 :(得分: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
答案 5 :(得分:0)
根据平台和python版本,python可能不会将内存释放回操作系统。见stackoverflow thread。也就是说,python不应该无休止地消耗内存。从您使用的代码判断,它似乎是python运行时中的错误,除非,urllib / sockets使用全局,我不相信它 - 在S60上的Python上归咎于它!
您是否考虑过其他内存泄漏源?无尽的日志文件打开,不断增加数组或smth像那样?如果它确实是套接字接口中的错误,那么您唯一的选择是使用子进程方法。
答案 6 :(得分:0)
我认为this可能是你的问题。为了总结该线程,Pys60的DNS查找中存在内存泄漏,您可以通过在内部循环外部移动DNS查找来解决它。