当前位置: 首页 > 面试题库 >

Python:垃圾回收失败?

邢昂然
2023-03-14
问题内容

考虑以下脚本:

l = [i for i in range(int(1e8))]
l = []
import gc
gc.collect()
# 0
gc.get_referrers(l)
# [{'__builtins__': <module '__builtin__' (built-in)>, 'l': [], '__package__': None, 'i': 99999999, 'gc': <module 'gc' (built-in)>, '__name__': '__main__', '__doc__': None}]
del l
gc.collect()
# 0

关键是,在所有这些步骤之后,此python进程在我的机器上的内存使用率约为30%(Python
2.6.5,是否可应要求提供更多详细信息?)。这是top输出的摘录:

 PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND  
5478 moooeeeep 20   0 2397m 2.3g 3428 S    0 29.8   0:09.15 ipython

分别 ps aux

moooeeeep 5478  1.0 29.7 2454720 2413516 pts/2 S+   12:39   0:09 /usr/bin/python /usr/bin/ipython gctest.py

根据该文档为gc.collect

由于特定的实现,尤其是int和,并非某些空闲列表中的所有项目都可能无法释放float

这是否意味着,如果我(暂时)需要大量的不同intfloat数字,我需要这个导出到C / C ++,因为Python的GC没有释放内存?

更新资料

正如本文所建议的,可能是解释者应受责备:

这是因为您已经同时创建了500万个整数,每个int对象占用12个字节。“为了速度”,Python为整数对象维护了一个内部空闲列表。不幸的是,这份免费清单是不朽的,而且规模不限。花车还使用不朽且不受限制的自由名单。

但是问题仍然存在,因为我无法避免这种数量的数据(来自外部源的时间戳/值对)。我真的被迫放弃Python并回到C / C ++吗?

更新2

Python实现可能确实是这种情况。找到此答案可以最终解释问题和可能的解决方法。

不幸的是(取决于您的Python版本和版本),某些类型的对象使用“自由列表”,这是一种整洁的局部优化,但可能会导致内存碎片,特别是通过使越来越多的“内存”仅用于特定类型的对象而引起的内存碎片。因此无法使用“普通基金”。

确保大量但临时使用内存的唯一确实可靠的方法是在完成后将所有资源都返还给系统,这是让使用发生在子进程中,该进程需要大量内存,然后终止。在这种情况下,操作系统将完成其工作,并乐意回收子进程可能吞没的所有资源。幸运的是,该multiprocessing模块使这种操作(过去很痛苦)在现代版本的Python中还不错。

在您的用例中,似乎子过程累积一些结果并确保这些结果可用于主过程的最佳方法是使用半临时文件(我指的是半临时文件,而不是那种关闭后会自动消失,只会删除您用完后会明确删除的普通文件)。


问题答案:

发现这也可以由Alex Martelli在另一个话题中回答。

不幸的是(取决于您的Python版本和版本),某些类型的对象使用“空闲列表”,这是一种整洁的局部优化,但可能会导致内存碎片,特别是通过为特定类型的对象分配更多的“专用”内存来实现。因此无法使用“普通基金”。

确保大量但临时使用内存的唯一确实可靠的方法是在完成后将所有资源都返还给系统,这是让使用发生在子进程中,该进程需要大量内存,然后终止。在这种情况下,操作系统将完成其工作,并乐意回收子进程可能吞没的所有资源。幸运的是,在现代版本的Python中,多处理模块使这种操作(以前是很痛苦的)变得不太糟糕。

在您的用例中,似乎子过程累积一些结果并确保这些结果可用于主过程的最佳方法是使用半临时文件(我指的是半临时文件,而不是那种关闭后会自动消失,只会删除您用完后会明确删除的普通文件)。

幸运的是,我能够将占用大量内存的工作分成多个单独的块,这使解释器在每次迭代后实际上都能释放临时内存。我使用以下包装器将内存密集型功能作为子进程运行:

import multiprocessing

def run_as_process(func, *args):
    p = multiprocessing.Process(target=func, args=args)
    try:
        p.start()
        p.join()
    finally:
        p.terminate()


 类似资料:
  • 问题内容: 我创建了一些python代码,该代码在一个循环中创建了一个对象,并且在每次迭代中均使用新的相同类型的对象覆盖了该对象。这完成了10.000次,Python每秒占用7mb的内存,直到使用了我的3gb RAM。有谁知道从内存中删除对象的方法吗? 问题答案: 您没有提供足够的信息-这取决于您要创建的对象的详细信息以及您在循环中对该对象所做的其他操作。如果对象未创建循环引用,则应在下一次迭代时

  • 垃圾回收 我们对生产中花了很多时间来调整垃圾回收。垃圾回收的关注点与Java大致相似,尽管一些惯用的Scala代码比起惯用的Java代码会容易产生更多(短暂的)垃圾——函数式风格的副产品。Hotspot的分代垃圾收集通常使这不成问题,因为短暂的(short-lived)垃圾在大多情形下会被有效的释放掉。 在谈GC调优话题前,先看看这个Attila的报告,它阐述了我们在GC方面的一些经验。 Scal

  • 对于开发者来说,JavaScript 的内存管理是自动的、无形的。我们创建的原始值、对象、函数……这一切都会占用内存。 当我们不再需要某个东西时会发生什么?JavaScript 引擎如何发现它并清理它? 可达性(Reachability) JavaScript 中主要的内存管理概念是 可达性。 简而言之,“可达”值是那些以某种方式可访问或可用的值。它们一定是存储在内存中的。 这里列出固有的可达值的

  • 垃圾收集,引用计数,显式分配 和所有的现代语言一样,OCaml提供垃圾收集器,所以你不用像C/C++一样显式地分配和释放内存。 JWZ在他的文章 "Java sucks" rant(Java蛋疼(怒)!): 第一个好家伙是Java没有 free()。其他的都没有所谓了。这几乎掩盖了所有的缺点,不管有多糟糕, 这个有点让后续文档基本都没有意义了,但是...(译注:但是啥大家自己看吧) OCaml的垃

  • 本文向大家介绍Python垃圾回收机制?相关面试题,主要包含被问及Python垃圾回收机制?时的应答技巧和注意事项,需要的朋友参考一下 引用计数 标记清除 分代回收  

  • 主要内容:垃圾回收器函数,实例Lua 采用了自动内存管理。 这意味着你不用操心新创建的对象需要的内存如何分配出来, 也不用考虑在对象不再被使用后怎样释放它们所占用的内存。 Lua 运行了一个垃圾收集器来收集所有死对象 (即在 Lua 中不可能再访问到的对象)来完成自动内存管理的工作。 Lua 中所有用到的内存,如:字符串、表、用户数据、函数、线程、 内部结构等,都服从自动管理。 Lua 实现了一个增量标记-扫描收集器。 它使用