生产环境下DML条件日志的性能优化方案问询
DML代码日志语句的编译期优化问题
我希望优化生产环境中DML代码的运行速度。据了解,如下log语句:
log info, <n>: <string>;
在可执行文件中至少会被转换为一个if语句,因为需要检查log-level是否大于n。我希望像C语言的#define和#ifdef语句那样将该if语句从可执行文件中移除,目前找到的唯一方法是定义常量并检查,寄希望于编译器识别代码永不会执行而将其优化掉:
constant LOG = 1; // 甚至没办法定义布尔常量 if (LOG) log info, <n>: <string>;
我的问题如下:
- 是否有更高效、更优雅的实现方式?
- DML编译器或C编译器是否会将这段代码优化掉?
- 如何验证该代码已不在可执行文件(或中间C源代码)中?
问题1:更高效优雅的实现方式
DML本身支持编译条件指令,和C的预处理器逻辑类似,能直接在编译阶段把不需要的日志代码砍掉,比靠编译器优化靠谱多了:
- 用
#ifdef配合编译参数:编译生产环境代码时加自定义宏参数(比如-DNO_LOG),代码里这么写:#ifdef NO_LOG // 生产环境直接跳过,预编译阶段就删了这段 #else log info, <n>: <string>; #endif - 要是需要按日志级别控制,用
#if定义编译期常量:#define LOG_LEVEL 0 // 生产环境设0,info级别的日志直接不编译 #if LOG_LEVEL >= 1 log info, <n>: <string>; #endif
这种方式不用赌编译器会不会优化,直接从根源上把代码删掉,效率最高也最优雅。
问题2:编译器是否会优化掉常量判断的代码
只要LOG是编译期常量(比如你用constant定义的1或0),不管是DML编译器转中间C代码,还是后续的C编译器(GCC、Clang这些),只要开了基础优化(比如-O1及以上),都会把死代码删掉:
- 要是
LOG=0,if(LOG)里的日志代码会被当成永远不会执行的死代码,直接从中间C和最终可执行文件里消失; - 要是
LOG=1,编译器会把if(LOG)这个判断直接拿掉,只留里面的log语句,不会有多余的判断开销。
但要注意:如果DML编译器本身不支持常量折叠,或者编译时没开优化,可能不会触发这个优化,所以还是条件编译更稳。
问题3:验证代码是否被移除的方法
有两种直观的验证方式:
查看中间C源代码
大部分DML编译器会生成中间C文件,直接打开搜你日志里的特征字符串(比如<string>的内容):
- 搜不到的话,说明代码已经被剔除;
- 还能看到的话,就是没被优化掉。
检查最终可执行文件
- 字符串搜索:用
strings命令(Linux/macOS)扫描可执行文件里的文本内容:
搜不到就说明日志代码没进可执行文件;strings 你的可执行文件名 | grep "你的日志内容片段" - 反汇编查看指令:用
objdump(Linux)或otool(macOS)反汇编,定位原来日志代码所在的函数:
看不到objdump -d 你的可执行文件名 | grep -A 15 -B 5 "目标函数名"log相关的调用指令,就说明代码被删了; - 调试断点验证:用GDB或LLDB挂载到可执行文件上,在原来写日志的位置设断点,要是断点无法创建或命中不了,就说明那段代码不在可执行文件里。
内容的提问来源于stack exchange,提问作者njc
相关产品推荐
相关产品推荐

