【问题标题】:Python object instantiation from within another object - is it a memory leak?从另一个对象中实例化 Python 对象 - 是内存泄漏吗?
【发布时间】:2016-05-26 02:05:21
【问题描述】:

考虑以下小型 Python GUI 程序,用户可以在其中反复单击按钮以在窗口 1 和窗口 2 之间循环:

import tkinter

class Window1:
    def __init__(self, parent):
        # Initialize a new GUI window
        self.parent = parent
        self.window = tkinter.Toplevel(self.parent)
        self.window.title('Window 1')

        # Make a button to launch Window 2
        launch_window_2_button = tkinter.Button(self.window, text='Launch Window 2')
        launch_window_2_button.config(command=self.launch_window_2)
        launch_window_2_button.pack()

    def launch_window_2(self):
        self.window.destroy()
        Window2(self.parent)


class Window2:
    def __init__(self, parent):
        # Initialize a new GUI window
        self.parent = parent
        self.window = tkinter.Toplevel(self.parent)
        self.window.title('Window 2')

        # Make a button to launch Window 1
        launch_window_1_button = tkinter.Button(self.window, text='Launch Window 1')
        launch_window_1_button.config(command=self.launch_window_1)
        launch_window_1_button.pack()

    def launch_window_1(self):
        self.window.destroy()
        Window1(self.parent)


if __name__ == "__main__":
    # Initialize and hide the root GUI
    # (each class will spawn a new window that is a child of the root GUI)
    root = tkinter.Tk()
    root.withdraw()
    Window1(root) # Start by spawning Window 1
    root.mainloop()

问题 1:由于每个新类都是从另一个类中实例化的,这是否是内存泄漏?

问题 2:这是编写此应用程序的最正确和 Pythonic 的方式吗?

问题 3: 假设问题 1 的答案是否定的,如果我将 Window1(self.parent) 更改为 self.something = Window1(self.parent) 会怎样。既然有了引用,现在是不是内存泄漏了?

【问题讨论】:

  • 内存泄漏是指您在不再使用内存时不释放内存。例如,如果您有一个程序从文件中读取行,并且您为每一行分配新内存,但在读取下一行之前从未释放一行的内存,这就是内存泄漏。无法释放该内存,因为您不再拥有对它的引用,因此您的程序使用的内存量将不断增长。 Python 为您管理内存,在这种情况下,内存将自动释放。对象的实例化方式或位置与它无关。

标签: python object memory-leaks


【解决方案1】:

问题 1:由于每个新类都是从另一个类中实例化的,这是否是内存泄漏?

没有。而且我认为您在一些内存泄漏和未使用的对象引用之间感到困惑。 @kindall 在您的问题下的评论中很好地解释了这一点。

了解正在发生的事情的最好方法是知道tkinter.TopLevel(..) 构造函数是side-effects based. 它将在根对象中保存对您的窗口的引用,以便它知道如何处理各种窗口。 你的类的构造函数也是如此。一旦它创建了一个self.window 并且以某种方式让root 引用了它,它的工作就完成了。这个对象的引用也被持有,虽然没有明确(见下面对你的问题 3 的回答)。


问题 2:这是编写此应用程序的最正确和 Pythonic 的方式吗?

没有使用对象Window1Window2 对象的引用这一事实也让我感到不安。除此之外,我可能还会在对象中存储窗口元素(按钮等)的引用——它们可能不会立即使用,但它们可能会在以后使用。


问题 3:假设问题 1 的答案是否定的,如果我 更改了以下几行:

Window1(self.parent)

到:

self.something = Window1(self.parent)

既然有了引用,现在是不是内存泄漏了?

想想下面这行:

launch_window_2_button.config(command=self.launch_window_2)

为了使该行正常工作,tkinter 必须在某处存储self.launch_window2(以及因此self)的引用,因此您的self.something 根本没有做任何重要的事情.. :)

【讨论】:

  • 非常感谢!你能告诉我一个代码 sn-p 解决“没有使用对对象 Window1 和 Window2 对象的引用这一事实”吗?我不太明白。为什么我要在这个程序的上下文中引用这些窗口?
  • 在此程序的上下文中,您可能不希望引用 Window 对象。我只是在暗示没有一个让我很烦恼。就个人而言,我不喜欢深度嵌套函数存储对象引用的想法。它可能暗示了资源的“所有权”不佳。但由于这是一个图书馆,我认为您对此无能为力.. 可悲的是
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-31
  • 2018-12-13
  • 2011-10-11
  • 1970-01-01
  • 2018-04-18
  • 2012-09-12
  • 1970-01-01
相关资源
最近更新 更多