排查脚本里 f.read() 读 2.3G 的 access.log,容器内存上限 4G,进程跑到一半直接消失。dmesg 里留着 Out of memory: Killed process 4127 (python3)。碰到这种情况,我一般先确认改动有没有真的生效。

原因不复杂,read 不带参数会把整个文件读成一个 bytes 对象,2.3G 在内存里还要复制一份,解码成 str 再翻一倍。容器到上限后内核挑占用最大的进程下手,异常栈都来不及打。

「Python read 大文件内存」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。别只看报错的最后一行,往上看几行,真正的起因通常在上面。

with open('access.log', 'r', encoding='utf-8', errors='replace') as f:
    for line in f:
        parse(line)

同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。

具体做法是,改成逐行迭代 for line in f 内存只跟单行长度有关;需要按块处理就用 read(1048576) 循环读到空串为止;确实要整份载入就换 mmap 或流式解析 别在主进程里拼大对象;改完用 /usr/bin/time -v 看 Maximum resident set size。

最后用这个标准收尾,RSS 稳定在 80MB 左右 dmesg 不再出现 OOM 解析条数和 wc -l 对得上。

作者 9823189