我的程序正在使用大量的ram内存,它的作用是:
这是代码:
def show_image(self, cam):
while True:
start_time = time.time()
self.update_image(cam)
load = Image.open(cam.getPlace() + "/image.jpeg")
load.thumbnail((400, 300))
render = ImageTk.PhotoImage(load)
if cam.getPlace() == "FrontYard1":
try:
img1 = Label(image=render)
img1.image = render
img1.grid(row=0, column=0)
except:
print("Error")
elif cam.getPlace() == "FrontYard2":
try:
img2 = Label(image=render)
img2.image = render
img2.grid(row=0, column=1)
except:
print("Error")
elif cam.getPlace() == "Garden1":
try:
img3 = Label(image=render)
img3.image = render
img3.grid(row=1, column=0)
except:
print("Error")
else:
try:
img4 = Label(image=render)
img4.image = render
img4.grid(row=1, column=1)
except:
print("Error")
print("And " + str(time.time() - start_time) + " to run show image")
def update_image(self, cam):
os.remove(cam.getPlace()+"/image.jpeg")
if cam.getModel() == "Model":
urllib.request.urlretrieve(#link and folder to download the image)
else:
urllib.request.urlretrieve(#link and folder to download the image)
我尝试使用gc.collect(),但似乎无法正常工作。
答案 0 :(得分:4)
您的代码正在尝试创建无限数量的Label
对象,将每个对象隐藏在无限数量的其他标签后面。除非您拥有无限的内存,否则这显然会导致问题。
您想要在任何给定时间都是四个标签。您需要跟踪已创建的标签,理想情况下只是重复使用它们,否则,请销毁它们,而不仅仅是将它们隐藏在新标签后面。
当前,您的代码正在跟踪img1
到img4
变量中的标签,只是直到第一次显示图像时它们才被创建,所以您无法检查他们。因此,在循环之前,您要么要创建四个空标签,要么只需将变量设置为None
。然后,在循环内部,您可以执行此操作(假设您使用None
代替了空标签):
if cam.getPlace() == "FrontYard1":
try:
if img1 is None:
img1 = Label(image=render)
img1.grid(row=0, column=0)
else:
img1.image = render
# etc.
您可以通过将标签存储在dict中而不是四个单独的变量中来简化此操作:
imgs = {“Front Yard 1": img1, …}
…,然后用字典查找替换if / elif链:
img = imgs.get(cam.getPlace())
尽管在这里,您几乎肯定会希望使用空标签,而不是None
作为初始值。
请注意,您的程序还有另一个非常严重的问题。 while True:
循环显然永远不会返回到tkinter事件循环。这意味着您不会给tkinter一个更新显示的机会,也不会响应窗口系统中的鼠标事件或退出或其他事件,因此您的应用将无响应,并弹出沙滩球或沙漏或其他任何内容。 / p>
要解决此问题,您需要删除循环,而让您的方法只是检索和处理一张图像,然后调用after
要求tkinter下次在事件循环中再次调用它。
这还需要将这些本地img1
变量(或上面建议的字典imgs
)更改为实例变量。
如果您尝试使用后台线程来执行此任务,则从主线程以外的任何线程对tkinter小部件进行任何操作都是非法的。在某些平台上,这只会给您立即出现错误,或挂起GUI。在其他平台上,它似乎可以正常工作,但是偶尔会做一些奇怪的事情,甚至更糟。
如果您正在通过mtTkinter
上的Python 3分支(包含the Effbot Book中显示的Queue
逻辑)来解决此问题,那么实际上您在小部件上所做的一切发布消息以供主线程处理),则可以忽略此部分。但是,如果不是这样,则可以执行此操作,或者手动执行同一操作(如链接页面中所示),或者只是摆脱后台线程并使用after
。
在我们这样做的时候,仅显示except:
的裸Error
隐藏了任何可能出现的问题,使调试变得更加困难,因此您几乎永远都不要这样做。 / p>
此外,Label.image
作业真的是唯一可以在这里提出的地方吗?
将它们放在一起:
def __init__(self):
self.imgs = {}
img1 = Label()
img1.grid(row=0, column=0)
self.imgs["Frontyard1"] = img1
# ... likewise for 2-4
def show_image(self, cam):
start_time = time.time()
try:
self.update_image(cam)
load = Image.open(cam.getPlace() + "/image.jpeg")
load.thumbnail((400, 300))
render = ImageTk.PhotoImage(load)
img = self.imgs.get(cam.getPlace())
if img:
img.image = render
# What do you want to do if it's not one of the four expected?
# Your existing code just ignores the image but still counts time,
# so that's what I did here.
except Exception as e:
print(f"Error updating cam '{cam.getPlace()}: {e!r}")
else:
print("And " + str(time.time() - start_time) + " to run show image")
self.root.after(0, self.show_image, cam)
答案 1 :(得分:-1)
在快速查看后,如果删除了第二步而不是实际显示它,而是直接将其保存到计算机,这将有助于减少ram。您是否拥有有关在此过程中拥有多少RAM和计算机正在使用多少内存的详细信息?另一个可能是增加一个步骤以将图像格式化为特定大小,因为它可能太大而无法处理大量图像。