【问题标题】:Python Stops Running then causes memory to spikePython 停止运行然后导致内存激增
【发布时间】:2020-06-07 00:44:22
【问题描述】:

我正在使用 PyCharm 运行一个大型 Python3.7 脚本,并由 Django 接口,它逐行解析 txt 文件并处理文本。它卡在一个特别大的文件的某个点上,我一生都无法弄清楚原因。一旦卡住,PyCharm 根据任务管理器使用的内存在 5-10 秒内运行高达 100% 的可用内存,我必须手动停止执行(当它在其他文件上运行时和之前的内存使用率很低执行在大文件上停止)。

我已将问题缩小到以下循环:

i = 0
for line in line_list:
    label_tmp = self.get_label(line)  # note: self because this is all contained in a class
    if label_tmp in target_list:
        index_dict[i] = line
    i += 1
    print(i)  # this is only here for diagnostic purposes for this issue

这对我测试过的少数文件非常有效,但在问题文件上它将在第 2494 次迭代时停止(即当 i=2494 时)。即使我删除文件的第 2494 行或删除文件的前 10 行,它也会这样做——因此这排除了文件中任何特定行的代码中的错误——无论是什么,它都会停止运行在第 2494 行。

我构建了 self.get_label() 来生成一个日志文件,因为它是一个大函数。玩了一圈后,我开始怀疑它无论如何都会在一定数量的动作后停止运行。例如,我在 self.get_label() 的开头添加了以下虚拟行:

log.write('Check1\n')  
log.write('Check2\n')
log.write('Check3\n')
log.write('Check4\n')

在第 2494 次迭代中,日志文件中的最后一个条目是“Check2”。如果我对该功能进行一些调整,它将在检查 4 处停止;如果我进行其他调整,它将在迭代 2493 处停止,但在“Check1”处停止,甚至一直到函数结束。

我认为问题可能与日志文件中的内存有关,但即使我注释掉日志行,代码仍会停在第 2494 行(再一次,无论该行中实际包含的文本如何) ) 或第 2493 行,具体取决于我所做的更改。

无论我做什么,执行都会停止,然后根据任务管理器使用的内存运行到 100%。重要的是要注意,在执行卡住之前,内存不会大幅增加。

有人知道是什么原因造成的吗?我看不出代码有什么问题,而且它在执行一定数量的操作后停止执行这一事实表明我正在达到某种我不知道的基本限制。

【问题讨论】:

  • 这(固定的迭代次数)让我想到了递归限制之类的东西,然后 PyCham 冻结试图处理巨大的堆栈跟踪信息??
  • 在这种情况下,用户将在停止之前收到警报;甚至可以停止最大递归深度。在这种情况下,内存只会永远扩展,无需进一步执行代码

标签: python django memory pycharm


【解决方案1】:

只是想在询问几个月后提供解决方案。大多数有经验的编码人员可能都知道,write() 函数只将输出添加到缓冲区。因此,如果在缓冲区可以清除之前发生无限循环(它仅每隔几行清除一次,具体取决于缓冲区的大小),那么仍在缓冲区中的任何行都不会打印到文件中。这使它看起来是一种不同类型的问题(我认为问题是在实际有缺陷的行之前约 20-30 行;根据我更改代码的方式,缓冲区在不同的行上清除,这解释了为什么日志文件结束于进行不相关更改时的不同行)。当我将“write”替换为“print”时,我能够识别出导致循环的代码中的确切行。

为避免出现此类虚拟情况,我建议创建一个包含“flush”的自定义“write_to_file”函数,以便将每一行写入日志文件。我还为该自定义“write_to_file”函数添加了其他类型的保护,例如如果文件超过一定大小则不写入等。

【讨论】:

    【解决方案2】:

    您可以尝试使用 sys.getsizeof。那个字典一定发生了一些事情,会像疯了一样增加记忆。其他可以尝试的方法是使用您的常规终端/cmd。否则,我希望看到更多的代码。

    此外,您可以枚举您的 for 循环,而不是使用 i += 1。

    for i, line in enumerate(line_list):
    

    希望其中的一些帮助。

    (抱歉,没有足够的代表发表评论)

    【讨论】:

    • 我在字典上使用了这个,它的内存分配永远不会超过 9320 字节。此外,“get_label”函数在前 1000 多次迭代中返回 False,因此字典的大小不是罪魁祸首。我不愿发布更多代码,因为“get_label”函数的长度超过 250 行,并且还引用了其他几个函数。我只是想知道是否有人以前见过这样的问题以及他们做了什么来解决它 - 巨大的内存没有分配给任何函数中的任何变量,所以我什至不知道从哪里开始。我将尝试通过 CMD 创建一个新的虚拟环境
    • @Helios 我知道 PyCharm 的终端占用了一些内存。您是否尝试仅使用自己的终端/cmd?您的 get_label 方法中还有其他内容吗?喜欢在伐木旁边?如果没有,只需将 label_tmp 注释掉,看看是否有任何用途。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    • 2021-12-30
    • 1970-01-01
    相关资源
    最近更新 更多