直接用std::sort读大文件进内存会崩,因内存开销达原始数据3~5倍且syscall密集;应改用预分配buffer+指针切分、分块排序归并,并严格控制chunk数与缓冲策略。

直接用 std::sort 读大文件进内存排序会崩——不是慢,是根本跑不起来。10GB 文本行数据,std::bad_alloc 或系统 OOM killer 杀进程是常态。
为什么不能把整个文件 load 到 vector 再 sort
内存开销远超文件本身:每行 std::string 带堆分配、小字符串优化(SSO)失效、迭代器和临时缓冲叠加,实际占用常达原始数据的 3~5 倍。更关键的是,std::getline() 逐行读 + 构造 string 是 syscall 密集型操作,IO 效率极低。
- 避免
std::string存每行:改用预分配大 buffer(如 64MB),用read()批量读入,再手动扫描'\n'切分 - 排序对象别存整行:只存
char*指针 + 长度,std::vector<:pair size_t>></:pair>即可 - 写子文件时加
std::ios::binary,并用file.rdbuf()->pubsetbuf(buf, size)设置 1MB 输出缓冲区
分块大小和 chunk 数怎么设才不翻车
不是越大越好,也不是越多越快。核心矛盾是:单块太大 → 内存溢出;chunk 太多 → 归并时打开文件数超限(Linux 默认 1024)、堆操作变重、缓冲区总内存超标。
- 分块大小建议设为可用物理内存的 60%~70%,留足给 OS page cache 和后续归并缓冲
- chunk 数控制在 64 以内:超过后
O(log K)堆操作收益递减,但文件描述符和 buffer 占用线性增长 - 子文件名必须带零填充序号,如
chunk_0017.tmp,否则归并时无法按字典序正确加载
多路归并时磁盘读性能暴跌的真正原因
不是 CPU 不够,是 seekg() 随机跳转导致 SSD 也变成“慢盘”。顺序读吞吐能到 500MB/s+,随机读可能跌到 20MB/s 以下。
- 每个 chunk 流维护独立
std::ifstream+ 小缓冲区(如 8KB),预读一行到本地 buffer - 堆节点只存
{value_ptr, stream_id, line_len},value_ptr指向各自 buffer 起始,不拷贝数据 - 比较函数用轻量 functor,别用
std::function或虚函数调用 - 归并输出同样要用大 buffer +
pubsetbuf+binary模式
最容易被忽略的点:归并阶段才是真正的性能瓶颈,而它几乎完全由 IO 模式决定——不是算法逻辑,是缓冲区大小、预读策略、指针管理这些底层细节。一旦开始 seek,就等于放弃 SSD 的全部优势。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











