在 python 中引发 outOfMemoryException 有多容易?

how easy is to cause an outOfMemoryExeption in python?

我在 python 中使用 pygame 编写了一个拼写蜜蜂程序,它工作正常,但我一直在用 7 个单词测试它,而不是更多。
我担心,如果与 300 个单词一起使用,它可能会导致内存被填满。 请记住有 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 位地址 space 的限制,约为 4 GB。
  • 您的计算机可能使用磁盘将虚拟内存增加到超过 RAM 大小。因此,即使您只有 1 GB RAM,您也可能会发现您可以在程序中使用 3 GB 内存。
  • 对于像您正在使用的小单词列表,除非您的程序有错误,否则您几乎 永远不会 运行 内存不足。根据我的经验,OutOfMemory 几乎总是因为我犯了一个错误。

你真的不用担心。 Python 内存不足,不会导致仅仅 600 个单词出现问题。

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

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

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

获取 Python list 对象的大小意味着您 只是获取列表对象内存需求 ,而不是存储的任何内容 'in'名单。您可以重复将同一对象添加到列表中,但不会得到副本,因为 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 的​​机器上,你不会有任何问题。请注意,我将 whole 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 的内存,用于将近 23.6 万个单词。

如果您担心程序越大,对象越多,您也可以使用 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() 测量值。