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无法分配足够的内存