readlines()会将整个文件一次性加载进内存生成列表,导致内存暴涨甚至崩溃;而for line in f利用迭代器惰性读取,内存占用恒定,但仅适用于行边界清晰的文本。

readlines() 会把整个文件所有行一次性加载进内存,生成一个巨大的 list,不是“慢”,而是根本没打算流式处理——程序崩溃不是偶然,是设计使然。
为什么readlines()必然吃光内存?
它底层先调用 f.read() 把全部字节读进来,再按 \n 切分,为每一行新建一个 str 对象,最后塞进一个新 list。哪怕文件只有 1GB 文本,Python 字符串开销 + list 的指针数组,实际内存占用常达 2–3GB。
常见错误现象包括:
-
MemoryError直接抛出,进程退出 -
ps aux显示 Python 进程 RSS 突增至数 GB - 在容器或低配云服务器上被 OOM Killer 杀掉(
dmesg | tail可查)
for line in f 为什么不会崩?
文件对象 f 是迭代器,for line in f 底层调用 f.__next__(),每次只从内核缓冲区解析出一行(含换行符),构造一个 str,交给你的处理逻辑;上一行对象一旦失去引用,就立即被 GC 回收。
内存占用始终稳定在「单行最大长度 + 少量缓冲」级别,通常几十 KB 到几 MB。
但要注意几个关键点:
- 必须用
with open()或显式f.close(),否则文件句柄泄漏可能掩盖内存问题 - 如果某行本身超长(比如单行 500MB 的 base64),这一行仍会 OOM —— 这是数据格式问题,和读取方式无关
- 编码错误(如用
utf-8解码含二进制垃圾的 log)可能导致某行解码失败并卡住,看似“内存涨”,实为阻塞
什么时候不能用 for line in f?
当文件没有换行符(如二进制 dump、自定义帧格式)、或需要跨行匹配正则(如多行日志堆栈)、或要随机跳转位置时,for line in f 失效,就得手动切块读。
核心是用 f.read(chunk_size) 控制缓冲区,自己拼接未闭合的行:
-
chunk_size推荐设为8192或65536(8KB 或 64KB) - 太小(如
1024)会导致系统调用频繁、I/O 效率骤降 - 太大(如
100MB)又失去内存控制意义 - 换行符归属、BOM 处理、编码回退这些细节,一旦数据越界,立刻变成内存和逻辑双崩点
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











