我很确定我正在遭受内存泄漏,但我没有100%确定它是如何发生的。
我写的应用程序从URL下载2个图像,并将每组图像(称为事务)排队到队列中,由用户界面弹出并显示。图像非常大,平均大约2.5MB。因此,作为加速用户界面并使其响应更快的一种方法,我将每个事务图像预加载到wxImage对象中并存储它们。
当用户弹出另一个事务时,我将预加载的图像提供给一个窗口对象,然后将wxImage转换为位图,并将DC blit转换为窗口。然后窗口对象显示在面板上。
当用户完成事务时,我销毁窗口对象(可能是窗口消失,位图也是如此),事务数据结构被'None'覆盖。
但是,根据预先加载的图像数量,队列大小是否设置得很大并且是否一次完成,或者我是否让一个小的队列大小随着时间的推移而停止,它最终会崩溃。我真的不能让这件事发生.. :))
任何人都会看到我正在做的任何明显的逻辑错误? python垃圾收集?我不必处理内存问题。
[edit]这里是代码;)这是与下载图像的线程相关的代码 - 它在主线程中实例化运行GUI - 下载线程的主要功能是'fill_queue'功能:< / p>
def fill_queue(self):
while True:
if (self.len() < self.maxqueuesize):
try:
trx_data = self.download_transaction_data(self.get_url)
for trx in trx_data:
self.download_transaction_images(trx)
if self.valid_images([trx['image_name_1'], trx['image_name_2']]):
trx = self.pre_load_images(trx)
self.append(trx)
except IOError, error:
print "Received IOError while trying to download transactions or images"
print "Error Received: ", error
except Exception, ex:
print "Caught general exception while trying to download transactions or images"
print "Error Received: ", ex
else:
time.sleep(1)
def download_transaction_images(self, data):
""" Method will download all the available images for the provided transaction """
for(a, b) in data.items():
if (b) and (a == "image_name_1" or a == "image_name_2"):
modified_url = self.images_url + self.path_from_filename(b)
download_url = modified_url + b
local_filepath = self.cache_dir + b
urllib.urlretrieve(download_url, local_filepath)
urllib.urlcleanup()
def download_transaction_data(self, trx_location):
""" Method will download transaction data and return a parsed list of hash structures """
page = urllib.urlopen(trx_location)
data = page.readlines()
page.close()
trx_list = []
trx_data = {}
for line in data:
line = line.rstrip('|!\n')
if re.search('id=', line):
fields = re.split('\|', line)
for jnd in fields:
pairs = jnd.split('=')
trx_data[pairs[0]] = pairs[1]
trx_list.append(trx_data)
return trx_list
def pre_load_images(self, trx):
""" Method will create a wxImage and load it into memory to speed the image display """
path1 = self.cache_dir + trx['image_name_1']
path2 = self.cache_dir + trx['image_name_2']
image1 = wx.Image(path1)
image2 = wx.Image(path2)
trx['loaded_image_1'] = image1
trx['loaded_image_2'] = image2
return trx
def valid_images(self, images):
""" Method verifies that the image path is valid and image is readable """
retval = True
for i in images:
if re.search('jpg', i) or re.search('jpeg', i):
imagepath = self.cache_dir + i
if not os.path.exists(imagepath) or not wx.Image.CanRead(imagepath):
retval = False
else:
retval = False
return retval
此外,我想补充一点,有时候,在崩溃之前我在控制台中遇到特殊错误,它们看起来像是图像错误,但图像没有损坏,错误发生在所有图像的所有阶段。
申请转移太少 scanlines [2009-09-08 11:12:03]错误: JPEG:无法加载 - 文件可能是 损坏。 [2009-09-08 11:12:11] 调试:.... \ src \ msw \ dib.cpp(134): 'CreateDIBSection'因错误而失败 0x00000000(操作完成 成功)。
这些错误可以单独发生,也可以一起发生。我认为发生的事情是,在某些时候,内存会被破坏,接下来发生的任何事情,如果我加载新的事务,图像,或者进行裁剪操作 - 都需要潜水。
所以不幸的是,在尝试将预加载函数调用wxImage移动到主gui线程的建议后,我仍然得到错误 - 再次发生在将太多图像加载到内存中或者如果它们位于记忆太久了。然后,当我尝试裁剪图像时,我得到一个内存错误 - 有些东西正在腐败,无论是在前一种情况下我使用太多还是没有足够的(这没有任何意义,因为我已经将我的页面文件大小增加到天文比例)或在后一种情况下,时间长度导致泄漏或腐败
我认为我现在能够使用的唯一方法是使用调试器 - 是否有任何简单的方法来调试wxPython应用程序?我想特别看看内存使用情况。
我认为我需要预加载图像的主要原因是因为如果我在每个图像上调用wxImage(我一次显示两个),每次加载“事务”时,从一个事务到下一个事务的接口非常慢和笨重 - 如果我把它们加载到内存中它非常快 - 但后来我得到了我的内存错误。
答案 0 :(得分:2)
两个想法:
修改强> 您需要在GUI线程中实例化wx.Image,而不是下载线程(您的上述代码看起来就像您当前在非GUI线程中实例化的那样)。通常,这几乎总会在任何GUI工具包中引起许多问题。在这种情况下,您可以在wxPython邮件列表中搜索大量电子邮件。我个人会这样做: