python内存错误(有足够的可用内存)

Posted

技术标签:

【中文标题】python内存错误(有足够的可用内存)【英文标题】:python memory error (there are enough available memory) 【发布时间】:2012-10-03 18:51:28 【问题描述】:

我正在尝试计算文本文件中字符串的出现次数。 文本文件长这样,每个文件大约200MB。

String1 30
String2 100
String3 23
String1 5
.....

我想将计数保存到字典中。

count  = 
for filename in os.listdir(path):
    if(filename.endswith("idx")):
        continue
    print filename  
    f = open(os.path.join(path, filename))
    for line in f:
        (s, cnt) = line[:-1].split("\t")
        if(s not in count):
            try:
                count[s] = 0 
            except MemoryError:
                print(len(count))
                exit()
        count[s] += int(cnt)  
    f.close()
    print(len(count))

count[s] = 0 出现内存错误, 但我的计算机中还有更多可用内存。 我该如何解决这个问题? 谢谢!

更新: 我在这里复制了实际代码。 我的python版本是2.4.3,机器运行linux,内存48G左右,但是只消耗不到5G。代码停在len(count)=44739243

更新2: 字符串可以重复(不是唯一的字符串),所以我想将字符串的所有计数相加。我想要的操作只是读取每个字符串的计数。每个文件大约有 10M 行,我有 30 多个文件。我预计这个数字不到 1000 亿。

更新3: 操作系统是 linux 2.6.18。

【问题讨论】:

getStringCount 是什么样子的。 我假设f.close() 上面的三行在这里缩进不正确? getStringCount(line) 只返回字符串及其计数。看起来像 return line.split("\t") 关闭每个文件后尝试print(len(count))print(sys.getsizeof(count)),以了解字典的大小。 与内存无关:你可以使用 collections.defaultdict(int) 来简化你的代码 【参考方案1】:

cPython 2.4 可能存在大内存分配问题,即使在 x64 上也是如此:

$ python2.4 -c "'a' * (2**31-1)"
Traceback (most recent call last):
  File "<string>", line 1, in ?
MemoryError
$ python2.5 -c "'a' * (2**31-1)"
$

更新到最近的 python 解释器(如 cPython 2.7)以解决这些问题,并确保安装 64 位版本的解释器。

如果字符串的大小很重要(即比您的示例中的

import hashlib
# ...
for line in f:
    s, cnt = line[:-1].split("\t")
    idx = hashlib.md5(s).digest()
    count[idx] = count.get(idx, 0) + int(cnt)
# ...

【讨论】:

MD5:不如安全散列安全;不如快速散列快。为此,请使用 Python 的内置(快速、不安全)哈希。【参考方案2】:

我不确定为什么会发生这种崩溃。您的字符串的估计平均大小是多长? 4400 万个字符串,如果它们有点长,你也许应该考虑散列它们,正如已经建议的那样。缺点是,您失去了列出唯一键的选项,您只需检查字符串是否在您的数据中。

关于内存限制已经达到 5 GB,可能与您过时的 python 版本有关。如果您可以选择更新,请获取 2.7。相同的语法(加上一些额外的),没有问题。好吧,我什至不知道下面的代码是否仍然与2.4兼容,也许你必须再次踢掉with语句,至少你在2.7中会这样写。

与您的版本的主要区别是手动运行垃圾收集。此外,您可以提高 python 使用的内存限制。正如你所提到的,它只使用实际内存的一小部分,所以如果有一些奇怪的默认设置禁止它变大,试试这个:

MEMORY_MB_MAX = 30000
import gc
import os
import resource
from collections import defaultdict
resource.setrlimit(resource.RLIMIT_AS, (MEMORY_MB_MAX * 1048576L, -1L))

count  = defaultdict(int)
for filename in os.listdir(path):
    if(filename.endswith("idx")):
        continue
    print filename  
    with open(os.path.join(path, filename)) as f:
        for line in f:
            s, cnt = line[:-1].split("\t")
            count[s] += int(cnt)  
    print(len(count))
    gc.collect()

除此之外,我不明白你的行s, cnt = line[:-1].split("\t") 的含义,尤其是[:-1]。如果文件看起来像您记下的,那么这将删除您号码的最后一位。这是故意的吗?

【讨论】:

感谢您的回答!它适用于 python 2.7。我使用 '[:-1]' 的原因是删除 '\n'。 没关系。对行的迭代将删除它,即使它会保留,转换为 int 也会踢出任何周围的空白。放下它,不必为每一行复制字符串。应该是值得注意的,关于数据总量。【参考方案3】:

如果您只想计算唯一字符串的数量,则可以通过散列每个字符串来大大减少内存占用:

    (s, cnt) = line[:-1].split("\t")
    s = hash(s)

【讨论】:

以上是关于python内存错误(有足够的可用内存)的主要内容,如果未能解决你的问题,请参考以下文章

python pymssql 错误:18456,b'DB-Lib 错误消息 20010,严重性 8:\n无法分配足够的内存

尽管有足够的 RAM,但内存错误

为啥当我知道有足够的内存空间时 cudaMalloc 会给我一个错误?

中间件机器操作系统内核优化

没有足够的java内存是啥意思,怎么解决

keras上的多GPU训练错误(OOM)(足够的内存,可能是配置问题)