裸机环境下不能直接用默认new/delete,因缺乏OS堆管理器,operator new依赖malloc而裸机无其实现;即使自实现malloc,也难保障实时性、线程安全与内存池隔离,易致堆破坏。

为什么裸机环境下不能直接用默认的 new 和 delete
裸机没有操作系统提供的堆管理器(比如 malloc 底层依赖的 sbrk 或 mmap),C++ 运行时默认的 operator new 会尝试调用 malloc,而裸机链接时若没提供 malloc 实现,就会报 undefined reference to 'malloc'。更糟的是,即使你实现了 malloc,它若没做内存池隔离或线程安全处理,在中断上下文中调用 new 可能导致堆破坏。
如何全局重定向 operator new 和 operator delete
必须在链接前提供自定义版本,且要覆盖所有标准签名。裸机常用静态内存池 + 简单首次适配(first-fit)分配器。关键点:
- 重载必须是全局作用域,不能在类内或命名空间内(除非显式用
::operator new) - 要实现全部四个基础函数:
operator new(size_t)、operator new[](size_t)、operator delete(void*)、operator delete[](void*) - 推荐把内存池定义为
static uint8_t heap_pool[64*1024]这类编译期确定大小的数组,避免递归调用自身 - 分配失败时,裸机不抛异常,应返回
nullptr(需加nothrow版本或设置std::set_new_handler,但后者在裸机常被禁用)
示例骨架:
static uint8_t heap_pool[32*1024];
static size_t heap_offset = 0;
<p>void<em> operator new(size_t size) {
if (size == 0) size = 1;
if (heap_offset + size > sizeof(heap_pool)) return nullptr;
void</em> ptr = &heap_pool[heap_offset];
heap_offset += size;
return ptr;
}</p><p>void operator delete(void* ptr) noexcept {
// 简单版本:不回收,只留空实现(或做 assert 检查 ptr 是否在 pool 内)
}</p><p>// 别忘了 [] 版本,否则 vector 等容器会链接失败
void<em> operator new[](size_t size) { return operator new(size); }
void operator delete[](void</em> ptr) noexcept { operator delete(ptr); }
链接时遇到 undefined reference to 'operator delete(void*, std::nothrow_t const&)' 怎么办
这是 C++11 后新增的 nothrow 版本,编译器在某些构造(如 new(std::nothrow) T)中会隐式调用。裸机项目若没定义它,链接会失败。必须补全:
立即学习“C++免费学习笔记(深入)”;
void* operator new(size_t, const std::nothrow_t&) noexceptvoid* operator new[](size_t, const std::nothrow_t&) noexceptvoid operator delete(void*, const std::nothrow_t&) noexceptvoid operator delete[](void*, const std::nothrow_t&) noexcept
这些函数体可直接复用已有逻辑,例如:
void* operator new(size_t size, const std::nothrow_t&) noexcept {
return operator new(size);
}
注意:头文件需包含 <new> 才能使用 std::nothrow_t;若想彻底规避,就别在代码里写 new(std::nothrow)。
重定向后仍触发 malloc 调用的隐藏路径
有些标准库组件(如 std::string、std::vector)在部分 STL 实现中可能绕过 operator new,直接调用 malloc —— 尤其是 GCC 的 libstdc++ 在未定义 _GLIBCXX_USE_C99_MALLOC 时仍可能 fallback。解决方法:
- 强制链接自己的
malloc/free,哪怕只是包装成对operator new/operator delete的调用 - 编译时加
-D_GLIBCXX_DEPRECATED=和-D_GLIBCXX_USE_C99_MALLOC=0(视 toolchain 版本而定) - 更可靠的做法:禁用部分 STL 组件,用
-fno-exceptions -fno-rtti -D__STRICT_ANSI__,并手动实现最小可用容器
裸机上最省心的方案,其实是完全不用 std::vector 这类动态容器,改用固定长度数组 + 手动计数 —— 不是因为做不到重定向,而是因为内存碎片、无调试信息、无运行时检查,会让问题延后到硬故障才暴露。


















