python - 我的程序使用了大量内存,我该怎么办?

标签 python python-3.x tkinter ram

我的程序使用了大量的内存,它的作用是:

  1. 从在线相机下载图像。
  2. 在窗口(Tkinter 窗口)中显示图像
  3. 删除图像。
  4. 再次进行相同的过程(无限循环直到窗口关闭)

这是代码:

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() 但它似乎不起作用。

最佳答案

您的代码正在尝试创建无限数量的 Label 对象,并将每个对象隐藏在无限堆栈的其他标签后面。除非您有无限的内存,否则这显然会导致问题。

想要在任何给定时间都只是四个标签。您需要跟踪您创建的标签,最好重复使用它们,或者,如果没有,则销毁它们,而不是将它们隐藏在新标签后面。


目前,您的代码正在跟踪这些 img1img4 变量中的标签,但它们直到第一次显示图像时才会创建,所以你无法检查它们。因此,在循环之前,您要么想要创建四个空标签,要么只是将变量设置为 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.

您可以通过将标签存储在字典中而不是四个单独的变量中来简化此操作:

imgs = {“Front Yard 1": img1, …}

…然后用字典查找替换 if/elif 链:

img = imgs.get(cam.getPlace())

尽管在这里,您几乎肯定会想要使用空标签而不是 None 作为初始值。


顺便说一句,您的程序还有另一个非常严重的问题。 while True: 循环显然永远不会返回到 tkinter 事件循环。这意味着您不给 tkinter 机会更新显示,或响应鼠标事件或退出或窗口系统中的其他事件,因此您的应用程序将无响应并弹出沙滩球或沙漏或其他任何内容。

要解决此问题,您需要删除循环,让您的方法仅检索并处理一张图像,然后调用 after 来要求 tkinter 下次通过事件循环再次调用它。

这还需要将那些本地 img1 变量(或上面建议的字典 imgs)更改为实例变量。

如果您尝试使用后台线程来完成此任务,则从主线程以外的任何线程对 tkinter 小部件执行任何操作都是非法的。在某些平台上,这只会立即给出错误,或者挂起 GUI。在其他平台上,它似乎可以工作,但每隔一段时间就会做一些奇怪的事情 - 这甚至更糟糕。

如果您正在通过例如 mtTkinter 上的 Python 3 分支(它包装 the Effbot Book 中显示的 Queue 逻辑)来解决此问题,那么您所做的一切在小部件上实际上会发布一条消息供主线程处理),那么您可以忽略此部分。但如果没有,您想要这样做,或者手动执行相同的操作(如链接页面所示),或者只是摆脱后台线程并使用 after


当我们这样做时,一个仅打印 Error 的裸露 except: 隐藏了可能出现的任何问题,并使调试变得更加困难,因此您几乎不应该这样做。

此外,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)

关于python - 我的程序使用了大量内存,我该怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51367022/

相关文章:

python - 根据 pandas 中的索引绘制一行中的所有值

django - DRF Serializer 更新嵌套对象列表

python - 如何在Redis中保存复杂的数据结构?

python - Python中的for循环并从文件中读取输入

python - Crontab 在重新启动时不运行 Python 脚本

python - Python Pandas 中的 GroupBy 函数,如 SUM(col_1*col_2)、加权平均值等

c++ - Python:如何检查...?

python - Python GUI 中的实时绘图

Python 按钮图像边框

python - 是否可以获取 tkinter 文本中标记的数字索引(位置)?