交易逻辑中必须杜绝动态内存分配,因其会导致微秒级抖动升级为毫秒级超时;须用静态/栈内存替代堆分配,禁用STL动态容器与隐式分配函数,并通过编译拦截、符号检查和宏定义等手段确保零分配。

为什么 new、malloc 和 STL 容器在交易逻辑里是红线
关键交易路径(比如订单匹配、行情解析、风控检查)一旦触发动态分配,可能卡在内存页分配、锁竞争或 GC 式延迟(哪怕没有 GC,malloc 的 arena lock 也会阻塞),导致微秒级抖动变成毫秒级超时。这不是“尽量避免”,而是必须从编译期和运行期双重杜绝——连隐式分配都不能存在。
用静态/栈内存替代所有堆分配的实操要点
核心原则:所有对象生命周期可静态推导,大小在编译期已知。
-
禁用所有 STL 动态容器:不用
std::vector、std::string、std::map;改用std::array、固定长度char buf[256]、预分配的std::span(C++20)或自定义无分配器的环形缓冲区 -
禁止隐式分配函数:
std::to_string会 new,改用fmt::format_to(配合栈上 buffer)或std::to_chars(C++17,纯栈操作) -
构造函数不能含 new:所有类需满足
std::is_trivially_constructible_v,成员全为 POD 类型;若需初始化逻辑,用constexpr函数或 placement-new(但 placement-new 目标内存本身必须是静态/栈分配) -
第三方库必须审计:如用
boost::variant,确认其内部无 heap 分配;absl::string_view安全,但absl::StrCat不安全(可能触发临时std::string)
如何静态检测代码是否偷偷调用了分配函数
光靠人工 review 不可靠,必须进构建链路拦截。
- Clang/GCC 编译时加
-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free,再链接一个空实现的malloc,让任何调用直接链接失败 - 用
nm -C your_binary | grep -E "(malloc|operator new|_Znwm)"检查符号残留(注意 C++ name mangling) - 在关键模块头文件顶部加
#define new __ERROR_new_used__,强制编译报错(需配合-fno-operator-names防绕过) - 启用 AddressSanitizer 的
detect_stack_use_after_return=0+abort_on_error=1,配合自定义 alloc hook 捕获 runtime 分配(仅用于测试阶段)
STL 算法和异常机制带来的隐性分配风险
很多人以为只禁掉 new 就安全了,但以下行为仍可能间接触发分配:
立即学习“C++免费学习笔记(深入)”;
-
std::sort在某些标准库实现中(如 libstdc++ 的 introsort)会为 pivot 缓存分配临时内存;改用std::stable_sort(若数据量小)或手写无栈溢出的 bitonic sort(对固定长度数组) - 抛异常会调用
std::uncaught_exceptions()及栈展开逻辑,部分 ABI(如 Itanium)在展开时可能分配内存;交易代码必须noexcept所有函数,并用-fno-exceptions彻底关掉异常机制 -
std::function构造时若绑定 lambda 且捕获了大对象,可能触发内部堆分配;一律改用函数指针或std::visit+ variant - 日志宏若含
std::ostringstream或格式化字符串拼接,必须重写为snprintf到栈 buffer
最危险的不是你写了 new,而是你依赖的某个模板实例化、某个库的 debug 断言、甚至编译器插入的 stack probe,在特定优化等级下悄悄分配。每个头文件、每行 include、每个 third-party header,都得当作潜在分配源来质疑。


















