Python 中丢弃图像时出现内存泄漏

2024-04-16

我目前正在用 Python 编写一个简单的棋盘游戏,我刚刚意识到当图像重新加载时,垃圾收集不会从内存中清除丢弃的位图数据。仅当游戏启动或加载或分辨率更改时才会发生这种情况,但它会增加消耗的内存,所以我不能让这个问题得到解决。

重新加载图像时,所有引用都会传输到新图像数据,因为它绑定到与原始图像数据绑定到的同一变量。我尝试使用强制垃圾收集collect()但这没有帮助。

我写了一个小样本来演示我的问题。

from tkinter import Button, DISABLED, Frame, Label, NORMAL, Tk
from PIL.Image import open
from PIL.ImageTk import PhotoImage

class App(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.text = Label(self, text = "Please check the memory usage. Then push button #1.")
        self.text.pack()
        self.btn = Button(text = "#1", command = lambda : self.buttonPushed(1))
        self.btn.pack()

    def buttonPushed(self, n):
        "Cycle to open the Tab module n times."
        self.btn.configure(state = DISABLED) # disable to prevent paralell cycles
        if n == 100:
            self.text.configure(text = "Overwriting the bitmap with itself 100 times...\n\nCheck the memory usage!\n\nUI may seem to hang but it will finish soon.")
            self.update_idletasks()
        for i in range(n):      # creates the Tab frame whith the img, destroys it, then recreates them to overwrite the previous Frame and prevous img
            b = Tab(self)
            b.destroy()
            if n == 100:
                print(i+1,"percent of processing finished.")
        if n == 1:
            self.text.configure(text = "Please check the memory usage now.\nMost of the difference is caused by the bitmap opened.\nNow push button #100.")
            self.btn.configure(text = "#100", command = lambda : self.buttonPushed(100))
        self.btn.configure(state = NORMAL)  # starting cycles is enabled again       

class Tab(Frame):
    """Creates a frame with a picture in it."""
    def __init__(self, master):
        Frame.__init__(self, master = master)
        self.a = PhotoImage(open("map.png"))    # img opened, change this to a valid one to test it
        self.b = Label(self, image = self.a)
        self.b.pack()                           # Label with img appears in Frame
        self.pack()                             # Frame appears

if __name__ == '__main__':
    a = App()

要运行上面的代码,您将需要一个 PNG 图像文件。我的map.png的尺寸是1062×1062。作为 PNG,其大小为 1.51 MB;作为位图数据,其大小约为 3-3.5 MB。使用大图像可以轻松查看内存泄漏。

运行我的代码时的预期结果:python 的进程循环地消耗内存。当它消耗大约 500 MB 时,它会崩溃,但会再次开始耗尽内存。

请给我一些如何解决这个问题的建议。我很感激每一个帮助。谢谢。提前。


首先,你肯定没有内存泄漏。如果每当接近 500MB 并且从未超过它时它就会“崩溃”,那么它就不可能泄漏。


我的猜测是你根本没有任何问题。

当 Python 的垃圾收集器清理东西时(通常在 CPython 中完成后立即发生),它通常不会实际将内存释放给操作系统。相反,它会保留它以备将来需要时使用。这是有意为之的——除非您破坏交换,否则重用内存比不断释放和重新分配内存要快得多。

另外,如果 500MB 是虚拟内存,那么在现代 64 位平台上这根本不算什么。如果它没有映射到物理/常驻内存(或者在计算机空闲时映射,但否则很快就被丢弃),那么这不是问题;只是操作系统对实际上免费的资源很好。

更重要的是:是什么让你认为存在问题?是否有任何实际症状,或者只是程序管理器/活动监视器/顶部/任何让您害怕的东西? (如果是后者,请查看其他程序。在我的 Mac 上,我当前有 28 个程序正在使用超过 400MB 的虚拟内存运行,并且我正在使用 16GB 中的 11 个,尽管虚拟内存不足 3GB实际上,如果我启动逻辑,那么内存的收集速度将快于逻辑使用它的速度;在那之前,操作系统为什么要浪费精力取消内存映射(特别是当它无法确保某些进程不会这样做时)去询问后来没有使用的内存)?


但如果有is一个真正的问题,有两种方法可以解决。


第一个技巧是在子进程中执行所有内存密集型操作,您可以杀死并重新启动以恢复临时内存(例如,通过使用multiprocessing.Process or concurrent.futures.ProcessPoolExecutor).

这通常会使事情变得更慢而不是更快。当临时内存主要是直接进入 GUI 的东西时,这显然不容易做到,因此必须驻留在主进程中。


另一种选择是找出内存的使用位置,而不是同时保留这么多对象。基本上,这有两个部分:

首先,在每个事件处理程序结束之前释放所有可能的内容。这意味着调用close在文件上,或者deling 对象或将所有对它们的引用设置为None, 呼叫destroy在不可见的 GUI 对象上,最重要的是,不存储对不需要的东西的引用。 (你真的需要保留PhotoImage使用后周围?如果这样做,有什么方法可以按需加载图像吗?)

接下来,确保您没有参考周期。在 CPython 中,只要不存在循环,垃圾就会立即清除,但如果有,它们会一直闲置,直到循环检查器运行。您可以使用gc module http://docs.python.org/3/library/gc.html调查此事。一件非常快速的事情就是经常尝试一下:

print(gc.get_count())
gc.collect()
print(gc.get_count())

如果您看到大幅下降,则说明存在周期。你必须向内看gc.getobjects() and gc.garbage,或附加回调,或只是推理您的代码以准确找到循环的位置。对于每一个,如果你真的不需要双向参考,那就去掉一个;如果这样做,请将其中一个更改为weakref.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 中丢弃图像时出现内存泄漏 的相关文章

随机推荐

  • 如何检查淘汰赛中的包含

    我正在使用淘汰赛 我有一个 html 页面 我想在其中检查具有某些值的字符串 就像我有一个字符串 A B C D F G H I 一样 我只想用剔除 if 检查 html 中的这个字符串 模型 var viewModel function
  • Spark SQL 广播哈希连接

    我正在尝试使用 SparkSQL 对数据帧执行广播哈希连接记录在这里 https spark apache org docs latest sql performance tuning html join strategy hints fo
  • 使用参考访问地图[重复]

    这个问题在这里已经有答案了 我尝试循环遍历地图 将其作为指向函数的指针传递 但我找不到访问元素的方法 这是代码 func refreshSession sessions map string Session now time Now for
  • Gradle 任务未显示在 Android Studio 4.2 的 gradle 工具窗口中

    我刚刚将 Android Studio 更新到版本 4 2 我很惊讶在我的项目中没有看到 Gradle 任务 在之前的版本 4 1 3 中 我可以看到如下所示的任务 但现在我只看到4 2版本中的依赖项 我尝试清除 Android Studi
  • 通过phpmailer批量发送邮件

    我正在使用 phpmailer 向我的订阅者发送批量电子邮件 但我面临一个可怕的问题 即当我向订阅者发送电子邮件时 每个订阅者都会多次收到相同的电子邮件 有些人获得了 4 次 有些人获得了 14 次 我正在通过 Mysql 表获取 flag
  • 如何确定用户在 JavaScript 中运行的是哪个版本的 IE?

    在一些现有代码中 有一个测试 通过检查对象 Browser Engine trident 是否已定义并返回 true 来查看用户是否正在运行 IE 但如何确定用户运行的是 IE6 或更早版本 还是 IE7 或更早版本 JavaScript
  • 如何在 MaterialButton 或 RaisingButton 上应用主题?

    有人可以帮助指出我们如何定义按钮的基本主题并在每个按钮上使用它吗 我到处寻找才发现textTheme但不是buttonTheme例子 Even on buttonTheme我们如何定义文本颜色 因为在按钮本身上我们可以直接这样做color
  • ASP.Net Core 从另一个控制器调用一个控制器

    在我的 ASP Net Core MVC 6 解决方案中 我有两组控制器 一组包含具有常规视图的网页 另一组包含 API 控制器 为了避免重复数据库逻辑 Web 控制器使用 API 控制器 目前 我正在通过将 DbContext 作为构造函
  • jQuery:多次淡入淡出div

    我在页面顶部有一个 div 我想淡入和淡出 3 次 我已经找到了一个问题 答案 它展示了如何通过将淡入淡出效果放入调用自身的函数中来进行无限循环淡入淡出 但我想知道指定有限数量的淡入淡出周期的最佳方法是什么 到目前为止 这就是我所拥有的 从
  • 资源调度问题

    我正在开发一个摩托车租赁网站 我遇到的问题是如何高效地解决为客人分配摩托车的问题 我知道如何以 愚蠢 的方式做到这一点 但我想知道是否有一种经典算法可以解决此类问题 这与将客人分配到酒店房间是同样的问题 在最后一个示例中 目标是通过不因调度
  • UIActionSheet 着色

    有人知道如何在 uikit 中为 uiactionsheet 着色吗 是的 因为它是一个 UIView 如 kmit 所描述的 您可以使用以下命令 addSubview 因此您可以添加自己的背景并使用 sendSubviewToBack 将
  • 在 JavaScript 中将字符串数组拆分为浮点数数组

    我正在尝试拆分一个称为 顶点 的字符串数组 并将其存储为浮点数组 目前字符串数组包含三个元素 0 1 0 1 1 0 1 1 0 我需要的是一个包含所有这些数字作为单独元素的浮点数组 0 1 0 1 1 0 1 1 0 我使用 split
  • 如何使用键盘快捷键打开弹出窗口? [复制]

    这个问题在这里已经有答案了 可能的重复 jQuery 的键盘快捷键 https stackoverflow com questions 593602 keyboard shortcuts with jquery 我想使用快捷键显示弹出窗口
  • 如何将自定义目标文件与 Haskell 库链接?

    我创建了一个 Haskell 包 它对 CUDA 代码中定义的函数进行 FFI 调用 我想在包构建期间将 cu 文件编译为对象 o 文件 并强制链接器将其链接 到目前为止 我尝试使用一种发现的技术这个问题 https stackoverfl
  • 使用plotly r 的多折线图

    我有一个数据框 我试图使用plotly作为多折线图来绘制它 下面是数据框的样子 Month considered pct x pct y pct
  • 如何阻止 VSCode 自动格式化删除括号内的空格?

    例如 当我写 foo bar 它将被格式化为 foo bar 我怎样才能让它保留2个空格 Edit 这是一个不同的问题如何更改 Visual Studio Code 中的缩进 https stackoverflow com question
  • 为什么在比较时将常量放在变量之前?

    我注意到我们的一些代码中存在以下语法有一段时间了 if NULL var or if 0 var 和类似的事情 有人可以解释一下为什么写这个的人选择这个符号而不是常见的符号var 0 way 这是风格问题 还是以某种方式影响性能 这是一种避
  • 为什么我在此语音识别代码中缺少 an4-1-1.match 文件?

    我在语音识别的解码部分遇到问题 我按照步骤操作here http www speech cs cmu edu sphinx tutorial html 当我输入 perl scripts pl decode slave pl 我收到这些错误
  • AWS从EBS切换到EFS

    我正在考虑从 AWS Elastic Block Storage 切换到 AWS Elastic Filesystem 主要是为了易于扩展 而且可共享存储似乎也不错 目前我有一个 debian EC2 实例和一个 EBS 卷 将数据从 EB
  • Python 中丢弃图像时出现内存泄漏

    我目前正在用 Python 编写一个简单的棋盘游戏 我刚刚意识到当图像重新加载时 垃圾收集不会从内存中清除丢弃的位图数据 仅当游戏启动或加载或分辨率更改时才会发生这种情况 但它会增加消耗的内存 所以我不能让这个问题得到解决 重新加载图像时