c++中new默认失败抛std::bad_alloc异常,非返回nullptr;若需返回nullptr,须用new(std::nothrow);解引用空指针或野指针直接导致段错误。

malloc 或 new 失败时返回 nullptr,不是抛异常
直接用 new int[1000000000] 分配几 GB 数组,多数情况下不会“崩溃”,而是返回 nullptr(C++11 起默认行为),但如果你没检查就解引用,才会触发段错误。Windows 上还可能弹出“内存不足”对话框;Linux 下通常静默失败,后续访问才 segfault。
关键点:这不是语法或编译问题,是运行时资源限制。必须显式检查分配结果:
int* arr = new (std::nothrow) int[size];
if (!arr) {
std::cerr
-
std::nothrow是必须的——否则new在失败时抛std::bad_alloc,不捕获就 terminate -
malloc同理:int* arr = (int*)malloc(size * sizeof(int));,失败返回nullptr,不抛异常 - 64 位程序才能可靠申请 >2GB 连续虚拟内存;32 位进程通常受限于 2–3GB 用户空间,即使物理内存充足也会失败
用 mmap(Linux/macOS)或 VirtualAlloc(Windows)绕过堆管理器碎片
标准堆分配器(malloc/new)依赖连续虚拟地址空间,而大数组常因堆碎片无法满足。系统级内存映射 API 可直接向内核申请大块匿名内存,成功率更高:
Linux/macOS 示例:
#include <sys>
int* arr = (int*)mmap(nullptr, bytes, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (arr == MAP_FAILED) {
perror("mmap failed");
return;
}</sys>
-
MAP_ANONYMOUS表示不关联文件,纯内存 - 分配后内存是 lazy-allocated(首次访问才真正分配物理页),所以
mmap很快,但第一次遍历仍可能触发 OOM killer - 释放用
munmap(arr, bytes),不是free
Windows 对应用 VirtualAlloc:
int* arr = (int*)VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!arr) { /* handle error */ }
别硬扛——改用 std::vector + reserve 不解决大数组问题
std::vector 底层仍是 new,reserve(n) 只预分配容量,不改变构造行为;resize(n) 会初始化所有元素,更慢、更易失败。它不帮你突破地址空间或物理内存限制。
- 对超大数组,
vector的优势仅在自动管理生命周期,而非提升成功率 - 如果只需随机读写、不需初始化,裸指针 +
mmap/VirtualAlloc更直接 - 若需部分加载(如处理 TB 级数据),应考虑内存映射文件(
mmap文件路径 /CreateFileMapping),而非全载入内存
检查 ulimit 和系统可用内存才是第一步
很多“分配失败”根本不是代码问题,而是环境限制:
- Linux 下运行
ulimit -v查看虚拟内存上限(-v)和地址空间(-as),ulimit -v unlimited可解除软限制(需权限) -
free -h或cat /proc/meminfo看MemAvailable,注意:即使空闲内存多,也可能因缺乏连续区域失败 - Windows 中,32 位程序默认只有 2GB 用户空间,需链接时加
/LARGEADDRESSAWARE才能使用 3GB(x86)或 4GB(x64)
真正难的不是调哪个函数,是判断“该不该全放内存里”——几十 GB 数组,大概率该切分、该流式处理、该换存储结构。硬刚地址空间边界,迟早撞上内核的 OOM killer 或 std::bad_alloc。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











