上限内存限制?

32 投票
5 回答
158670 浏览
提问于 2025-04-16 07:38

Python的内存有没有限制?我在用一个Python脚本计算一个至少150MB大小的文件的平均值。

根据文件的大小,有时候我会遇到MemoryError这个错误。

有没有办法给Python分配更多的内存,这样我就不会遇到这个错误了?


补充说明:下面是代码

注意:文件的大小差别很大(最大可以达到20GB),最小的文件大小是150MB。

file_A1_B1 = open("A1_B1_100000.txt", "r")
file_A2_B2 = open("A2_B2_100000.txt", "r")
file_A1_B2 = open("A1_B2_100000.txt", "r")
file_A2_B1 = open("A2_B1_100000.txt", "r")
file_write = open ("average_generations.txt", "w")
mutation_average = open("mutation_average", "w")

files = [file_A2_B2,file_A2_B2,file_A1_B2,file_A2_B1]

for u in files:
    line = u.readlines()
    list_of_lines = []
    for i in line:
        values = i.split('\t')
        list_of_lines.append(values)

    count = 0
    for j in list_of_lines:
        count +=1

    for k in range(0,count):
        list_of_lines[k].remove('\n')

    length = len(list_of_lines[0])
    print_counter = 4

    for o in range(0,length):
        total = 0
        for p in range(0,count):
            number = float(list_of_lines[p][o])
            total = total + number
        average = total/count
        print average
        if print_counter == 4:
            file_write.write(str(average)+'\n')
            print_counter = 0
        print_counter +=1
file_write.write('\n')

5 个回答

18

Python可以使用它所处环境中的所有可用内存。我简单的“内存测试”在使用了大约

1959167 [MiB]

的情况下,在ActiveState Python 2.6上崩溃了:

 239000 [MiB]

而在jython 2.5上,它崩溃得更早:

 239000 [MiB]

可能我可以配置Jython来使用更多内存(因为它使用的是JVM的限制)

测试应用:

import sys

sl = []
i = 0
# some magic 1024 - overhead of string object
fill_size = 1024
if sys.version.startswith('2.7'):
    fill_size = 1003
if sys.version.startswith('3'):
    fill_size = 497
print(fill_size)
MiB = 0
while True:
    s = str(i).zfill(fill_size)
    sl.append(s)
    if i == 0:
        try:
            sys.stderr.write('size of one string %d\n' % (sys.getsizeof(s)))
        except AttributeError:
            pass
    i += 1
    if i % 1024 == 0:
        MiB += 1
        if MiB % 25 == 0:
            sys.stderr.write('%d [MiB]\n' % (MiB))

在你的应用中,你一次性读取整个文件。对于这么大的文件,你应该逐行读取。

20

你现在是把整个文件都读到内存里了(line = u.readlines()),如果文件太大就会出问题(你提到有些文件大到20GB),这就是你的问题所在。

更好的做法是逐行读取:

for current_line in u:
    do_something_with(current_line)

这是推荐的方法。

在你的脚本后面,你做了一些很奇怪的事情,比如先计算列表里的所有项目数量,然后再根据这个数量构建一个for循环。为什么不直接遍历这个列表呢?你的脚本目的是什么?我觉得这样做可以简单很多。

这就是像Python这样的高级语言的一个优点(和C语言相比,C语言需要你自己处理这些琐事):让Python来帮你处理循环,只在内存中保留你实际需要的数据。

另外,看起来你在处理TSV文件(制表符分隔值),你应该看看csv模块,它会帮你处理所有的分割、去掉\n等操作。

35

(这是我第三次回答这个问题,因为我在最初的回答中误解了你的代码,然后在第二次回答中犯了一个小但关键的错误——希望这次能解决问题。)

编辑: 由于这个回答似乎很受欢迎,我对其进行了几处修改,以改善实现方式——大多数修改都不是很大。这是为了让大家在使用这个模板时,能有一个更好的基础。

正如其他人指出的,你遇到的 MemoryError 问题,很可能是因为你试图将大文件的全部内容一次性读入内存。而且,接着又通过创建一个包含每行字符串值的列表的列表,实际上又加倍了所需的内存。

Python的内存限制取决于你电脑和操作系统可用的物理内存和虚拟内存磁盘空间。即使你没有用完所有内存,你的程序“运行”了,但使用这些内存可能不切实际,因为速度太慢。

总之,避免这个问题最明显的方法就是一次处理一个文件的单行内容,这意味着你需要逐步进行处理。

为了实现这一点,需要保持一个每个字段的运行总和列表。当处理完成后,可以通过将对应的总值除以读取的总行数来计算每个字段的平均值。完成后,这些平均值可以打印出来,并写入其中一个输出文件。我也特别努力使用非常描述性的变量名,以便让它更容易理解。

try:
    from itertools import izip_longest
except ImportError:    # Python 3
    from itertools import zip_longest as izip_longest

GROUP_SIZE = 4
input_file_names = ["A1_B1_100000.txt", "A2_B2_100000.txt", "A1_B2_100000.txt",
                    "A2_B1_100000.txt"]
file_write = open("average_generations.txt", 'w')
mutation_average = open("mutation_average", 'w')  # left in, but nothing written

for file_name in input_file_names:
    with open(file_name, 'r') as input_file:
        print('processing file: {}'.format(file_name))

        totals = []
        for count, fields in enumerate((line.split('\t') for line in input_file), 1):
            totals = [sum(values) for values in
                        izip_longest(totals, map(float, fields), fillvalue=0)]
        averages = [total/count for total in totals]

        for print_counter, average in enumerate(averages):
            print('  {:9.4f}'.format(average))
            if print_counter % GROUP_SIZE == 0:
                file_write.write(str(average)+'\n')

file_write.write('\n')
file_write.close()
mutation_average.close()

撰写回答