简体   繁体   中英

My program uses a lot of ram memory, what can I do?

My program is using a lot of ram memory, what it does is this:

  1. Downloads an image from an online camera.
  2. Shows the image in the window (Tkinter window)
  3. Deletes the image.
  4. The same process again (infinite loop untill the window is closed)

This is the code:

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)

I tried using gc.collect() but it doesn't seems to be working.

Your code is attempting to create an infinite number of Label objects, hiding each one behind an infinite stack of other labels. This obviously leads to problems unless you have infinite memory.

What you want is just four labels at any given time. You need to keep track of the labels you've created and ideally just reuse them, or, if not, destroy them instead of just hiding them behind new ones.


Currently, your code is keeping track of the labels in those img1 through img4 variables, except that they don't get created until the first time they show an image, so you can't check them. So, before the loop, you'll either want to create four empty labels, or just set the variables to None . Then, inside the loop, you can do this (assuming you went with None instead of empty labels):

    if cam.getPlace() == "FrontYard1":
        try:
            if img1 is None:
                img1 = Label(image=render)
                img1.grid(row=0, column=0)
            else:
                img1.image = render
        # etc.

You could simplify this by storing the labels in a dict instead of four separate variables:

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

… and then replacing the if/elif chain with a dict lookup:

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

Although here, you're almost certainly going to want to go with empty labels instead of None for the initial values.


As a side note, your program has another very serious problem. A while True: loop obviously never returns to the tkinter event loop. This means you don't give tkinter a chance to update the display, or respond to mouse events or quits or other events from the window system, so your app is going to be nonresponsive and pop up a beach ball or hourglass or whatever.

To fix this, you need to remove the loop and instead have your method just retrieve and process one image and then call after to ask tkinter to call it again the next time through the event loop.

This will also require changing those local img1 variables (or the dict imgs suggested above) into instance variables.

If you were trying to use a background thread for this task, it's illegal to do anything to tkinter widgets from any thread but the main thread. On some platforms, this will just give you an immediate error, or hang the GUI. On other platforms, it will seem to work, but every once in a while do something weird—which is even worse.

If you're working around this via, eg, a Python 3 fork on mtTkinter (which wraps the Queue logic shown in the Effbot Book , so everything you do on a widget actually posts a message for the main thread to process), then you can ignore this section. But if not, you want to either do that, or do the same thing manually (as shown in the linked page), or just get rid of the background thread and use after .


While we're at it, a bare except: that just prints Error is hiding any problems that might show up and making it harder to debug things, so you should almost never do that.

Also, is the Label.image assignment really the only place that can raise here?


Putting it all together:

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)

After quick review if you remove step two to not actual show it and just save it straight to the computer this will help cut down on the ram. Do you have any details on how much RAM you have and how much the computer is using during the process? Another could be adding a step to format the image to a certain size as it might be too large to process large quantities.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM