【问题标题】:how easy is to cause an outOfMemoryExeption in python?在 python 中导致 outOfMemoryExeption 有多容易?
【发布时间】:2019-04-26 21:15:05
【问题描述】:

我正在使用 pygame 在 python 中编写一个拼写蜜蜂程序,它运行良好,但我一直在用 7 个单词测试它,而不是更多。
我担心,如果与 300 个单词一起使用,可能会导致内存填满。 记住有 2 个数组:一个保存默认单词列表,另一个保存随机单词。

【问题讨论】:

  • 这可能取决于运行它的计算机。除非您在土豆上运行它,否则仅 300 个字符串不会导致内存问题。
  • 使用所有可用内存很容易a = 'a'*100000000000000000。但是 300 字不会对任何现代系统造成问题。
  • 300字不会用完你所有的记忆,不。
  • 1):记住它们是 600,因为它们是正常列表和随机列表。
  • 2) 假设它是 8Gb RAM

标签: python memory out-of-memory


【解决方案1】:

你真的不需要担心。 Python 不会像仅仅 600 个单词那样占用内存。

稍加注意,您可以直接测量内存需求。 sys.getsizeof() function 可让您测量给定 Python 对象的直接内存需求(仅直接内存,而不是它引用的任何内容!)。您可以使用它来测量单个字符串:

>>> import sys
>>> sys.getsizeof("Hello!")
55
>>> sys.getsizeof("memoryfootprint")
64

具体大小取决于 Python 版本和您的操作系统。 Python 字符串对象需要基本内存量来存储大量簿记信息,然后每个字符需要 1、2 或 4 个字节,具体取决于最高 Unicode 代码点。对于 ASCII,每个字母只有一个字节。 Python 3.7,在我的 Mac OS X 系统上使用 49 个字节作为簿记部分。

获取 Python list 对象的大小意味着您得到只是列表对象内存要求,而不是存储在“列表”中的任何内容。您可以重复将相同的对象添加到列表中,但不会得到副本,因为Python uses references for everything,包括列表内容。考虑到这一点。

让我们加载 300 个随机单词,并创建两个列表,看看内存需要什么:

>>> import random
>>> words = list(map(str.strip, open('/usr/share/dict/words')))  # big file of words, present on many computers
>>> words = random.sample(words, 300)  # just use 300
>>> words[:10]
['fourer', 'tampon', 'Minyadidae', 'digallic', 'euploid', 'Mograbi', 'sketchbook', 'annul', 'ambilogy', 'outtalent']
>>> import statistics
>>> statistics.mean(map(len, words))
9.346666666666666
>>> statistics.median(map(len, words))
9.0
>>> statistics.mode(map(len, words))
10
>>> sys.getsizeof(words)
2464
>>> sum(sys.getsizeof(word) for word in words)
17504

这是一个列表,包含 300 个唯一单词,平均长度刚刚超过 9 个字符,列表需要 2464 个字节,单词本身需要 17504 个字节。这甚至不到 20KB。

但是,您说,您有 2 个列表。但是第二个列表不会包含您的单词的副本,这只是对现有单词的更多引用,因此只需要另外 2464 个字节,即 2KB。

对于 300 个随机英文单词,在两个列表中,您的总内存需求约为 20KB 内存

在 8GB 机器上,您不会有任何问题。请注意,我将整个 words 文件一次性加载到我的计算机中,然后将其缩减为 300 个随机单词。这是整个初始列表需要多少内存:

>>> words = list(map(str.strip, open('/usr/share/dict/words')))
>>> len(words)
235886
>>> sum(sys.getsizeof(word) for word in words)
13815637
>>> sys.getsizeof(words)
2007112

这大约是 15MB 的内存,用于将近 236,000 个单词。

如果您担心具有更多对象的大型程序,您也可以使用tracemalloc library 获取有关内存使用的统计信息:

last = None
def display_memory_change(msg):
    global last
    snap = tracemalloc.take_snapshot()
    statdiff, last = snap.compare_to(last, 'filename', True), snap
    tot = sum(s.size for s in statdiff)
    change = sum(s.size_diff for s in statdiff)
    print('{:>20} (Tot: {:6.1f} MiB, Inc: {:6.1f} MiB)'.format(
        msg, tot / 2 ** 20, change / 2 ** 20))


# at the start, get a baseline
tracemalloc.start()
last = tracemalloc.take_snapshot()

# create objects, run more code, etc.

display_memory_change("Some message as to what has been done")

# run some more code.

display_memory_change("Show some more statistics")

使用上面的代码来衡量阅读所有这些单词:

tracemalloc.start()
last = tracemalloc.take_snapshot()
display_memory_change("Baseline")

words = list(map(str.strip, open('/usr/share/dict/words')))

display_memory_change("Loaded words list")

输出

            Baseline (Tot:    0.0 MiB, Inc:    0.0 MiB)
   Loaded words list (Tot:   15.1 MiB, Inc:   15.1 MiB)

确认我的sys.getsizeof() 测量结果。

【讨论】:

  • 也很有用
  • 如果我可以同时选择,我会
  • 抱歉,您只能将一个标记为已接受的答案。选择完全由您自己选择,不选择也是一种选择。
【解决方案2】:

找出答案的一个好方法是尝试一下。

你可以在你的程序中间写一行到print out how much memory it is using

import os
import psutil
process = psutil.Process(os.getpid())
print(process.memory_info().rss)

尝试使用不同数量的单词运行您的程序并绘制结果:

然后你可以预测需要多少单词才能用完所有的记忆。

需要记住的其他几点:

  • 如果您使用 32 位 Python,您的总内存将被 32 位地址空间限制为大约 4 GB。
  • 您的计算机可能使用磁盘来增加超出 RAM 大小的虚拟内存。因此,即使您只有 1 GB 的 RAM,您也可能会发现您可以在程序中使用 3 GB 的内存。
  • 对于像您正在使用的小单词列表,除非您的程序有错误,否则您几乎永远不会耗尽内存。根据我的经验,OutOfMemory 几乎总是因为我犯了一个错误。

【讨论】:

  • 操作系统内存分配不是衡量这一点的好方法,因为这发生在块中,而 Python 使用堆模型(这意味着它会请求更大的块)。
  • 改为使用tracemalloc snapshots
  • 那我该如何测量呢?
  • @MartijnPieters 这是一个很好的观点。当然,如果您即将使用整个 RAM,则操作系统内存使用量将是一个不错的近似值。
  • 请参阅 Python: Cannot replicate a test on memory usage 了解有关试图测量 Python 内存使用(不正确)的博文的具体讨论,linked gist 包括如何使用 tracemalloc 来测量内存使用。
猜你喜欢
  • 1970-01-01
  • 2015-04-24
  • 1970-01-01
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-17
  • 2014-12-24
相关资源
最近更新 更多