You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

读取59GB大文件拆分时触发Memory Error的技术咨询

大文件拆分触发Memory Error?来试试这些排查思路

嘿,我来帮你捋捋这个59GB大文件拆分时遇到的问题,结合你16GB内存的配置、全程内存占用低但突然报错的情况,给你几个实用的排查点和解决办法:

一、先查文件句柄泄漏——这大概率是元凶

你是按每行开头的ID拆分文件,对吧?如果你的代码里没及时关闭不再使用的文件句柄,哪怕系统内存看起来不高,当打开的文件数量达到系统限制(比如默认系统最多允许单个进程打开1024个文件),后续操作就可能触发内存相关的错误——因为系统要维护大量文件对象的元数据,这些数据累积到一定程度就会爆。

  • 怎么查?运行代码时,先找到你的Python进程PID(用ps aux | grep python),然后用lsof -p <你的PID>查看打开的文件数量,看看是不是一直在疯涨。
  • 解决办法:别把所有打开的文件都存在字典里一直不关闭。可以用LRU缓存来限制同时打开的文件数,比如只保留最近使用的1000个,超过数量就自动关闭最久没用到的文件(后面给你贴优化后的代码示例)。

二、检查Python的文件缓冲设置

默认情况下Python的文件对象会用系统默认的缓冲,但如果缓冲没及时刷新,会不会在某个节点突然占用大量内存?虽然你说全程内存低,但可以排查试试:

  • 可以在每次写入后手动调用flush(),或者打开文件时设置buffering=1(行缓冲模式),强制每次写完一行就刷到磁盘,减少内存里的缓冲数据。不过行缓冲会稍微慢一点,但对于你的场景来说,稳定性更重要。

三、确认有没有不小心把数据存进内存

你是逐行读取文件吧?别是不小心用了readlines()把整个59GB文件都塞进内存了——不过你说全程内存低,应该不是这个,但还是要确认代码里是for line in input_file:这种逐行迭代的方式,而不是一次性加载全部内容。
另外,如果你的文件里ID数量特别多(比如几百万个),用来映射ID和文件句柄的字典会越来越大,内存占用慢慢累积,到45GB的时候刚好达到临界点,就触发错误了。这时候还是要回到第一个点,限制同时打开的文件数。

四、看看系统层面的隐性内存占用

有时候你看Python进程的内存不高,但系统的交换空间(swap)被占满了,或者页缓存把可用内存吃光了,这时候系统会触发OOM(内存不足),导致Python抛出Memory Error。

  • 怎么查?运行代码时开个终端,用free -h实时监控系统内存和swap的使用情况,看看是不是swap被用完了,或者可用内存降到极低。
  • 解决办法:如果swap不够,可以临时加个交换分区;但更根本的还是优化代码的文件句柄管理,减少系统资源消耗。

五、给你的代码优化示例

从你贴的代码片段来看,大概是用字典存ID对应的文件句柄对吧?给你改个优化版,用LRU缓存限制同时打开的文件数:

from functools import lru_cache

input_path = "/home/.../folder2/aldk_tab_1mn.csv"
output_dir = "/home/.../folder1/"

# 限制最多同时打开1000个文件,超出就关闭最久未使用的
@lru_cache(maxsize=1000)
def get_output_file(line_id):
    output_path = f"{output_dir}/{line_id}.csv"
    # 用追加模式打开,避免覆盖已有内容
    return open(output_path, 'a')

try:
    with open(input_path, 'r') as input_file:
        for line in input_file:
            # 提取开头的ID,这里假设是CSV按逗号分割,你可以改成自己的提取逻辑
            line_id = line.split(',')[0].strip()
            output_file = get_output_file(line_id)
            output_file.write(line)
            # 可选:强制刷新缓冲,避免内存累积
            output_file.flush()
finally:
    # 最后一定要关闭所有打开的文件
    for file_obj in get_output_file.cache().values():
        file_obj.close()

六、其他小排查点

  • 检查文件里有没有异常行:比如某一行特别大,读取时突然占用大量内存?不过你运行了2小时才报错,大概率不是这个,但可以用wc -L <你的文件>看看最长行的长度,心里有数。
  • 升级Python版本:某些旧版本的Python在文件句柄管理上可能有bug,升级到3.8+的稳定版说不定能解决问题。

内容的提问来源于stack exchange,提问作者saias

火山引擎 最新活动