内存损坏:
说到调试我们不得不想起内存损坏,而内存损坏通常都是复写不属于自己的内存,或越界等。
至于常说的内存溢出和下溢指的是:超过当前块大小的内容写到其他内存块中。
对于访问释放内存来说 释放的内存可能还会再一次分配给用户。
一般released版本当释放后和申请的内存一样大时会很快分配给用户,dubug版本存在保护页机制, 既被释放的内存不会立即被内存管理器立即提供给用户。
这也是为什么一般在例行版本是发生的崩溃在调试版本中不会复现的原因。
未初始化变量在released上出问题的原因:
dubug版本默认变量是0原因:出于安全考虑,内核提供的物理内存页会依附到进程虚拟空间时呗清零,否则一个进程就可能通过未清理的物理内存页读取另一个进程的数据, released版本:大多使用寄存器,而寄存器对栈内存是真正的“随机”。
优化后的二进制:
发行版本相对于调试版本会少些调试功能。编译器会尝试各种算法以提高程序性能,而这些通常会在不影响语义情况下改变源程序的执行顺序或变量的存储时间和类型。
以下是一些区别:
-
内存分配上:调试版本会返回一个比申请内存更大的内存块,内存块前后会加一些字节序列,一但被意外写入或写出,会发生崩溃,用于跟踪内存泄露、验证已释放内存等。
-
断言语句,断言在发布版本完全消失
-
局部变量和函数参数存储位置:优化器会尽可能使用寄存器,另一面,编译器在调试构建中总会为局部变量和参数分配栈内存。(寄存器通常有随机切不可预测的值)
-
发布版本更快
-
执行顺序:发布版本源语句被四处移动以获得更好性能。:提取公共表达式,提取不变量,使用管道或者缓存等。,编译器认为不需要的代码,甚至可以删除,如果死逻辑代码。
-
局部变量或参数通常分配在占内存,需要时加载的寄存器中。
编译器视角中的类:对象的详细布局
聊完了内存损坏再来看看 编译器视角中的类的布局
-fump-lang-class
对于如下的类:
class SearchLink
{
virtual bool IsPrelinkLowerLink() = 0;
};
class LaneSearchLink : public SearchLink
{
virtual bool IsPrelinkLowerLink() {return 0;}
bool UpLevelEnabled() {return 0;}
};
int main(){return 1;}
生成的编译器视角中的类:
Vtable for SearchLink
SearchLink::_ZTV10SearchLink: 3 entries #3个条目
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI10SearchLink) #地址
16 (int (*)(...))__cxa_pure_virtual
Class SearchLink
size=8 align=8 #类大小为8 对齐为8字节对齐
base size=8 base align=8
SearchLink (0x0x7fc9d7a3b960) 0 nearly-empty #大小近似为0
vptr=((& SearchLink::_ZTV10SearchLink) + 16) #当前类地址偏移16字节为虚表地址
Vtable for LaneSearchLink
LaneSearchLink::_ZTV14LaneSearchLink: 3 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI14LaneSearchLink)
16 (int (*)(...))LaneSearchLink::IsPrelinkLowerLink
Class LaneSearchLink
size=8 align=8
base size=8 base align=8
LaneSearchLink (0x0x7fc9d78e41a0) 0 nearly-empty
vptr=((& LaneSearchLink::_ZTV14LaneSearchLink) + 16)
SearchLink (0x0x7fc9d7a3b9c0) 0 nearly-empty
primary-for LaneSearchLink (0x0x7fc9d78e41a0)
单提一嘴:
vptr=((& SearchLink::_ZTV10SearchLink) + 16)dynamic_cast 和 static_cast的实现原理也基于此
GDB查看程序的内存映射信息
info proc mappings
GDB启用表达式调试模式:可以更直观的看到一些基本信息
set debug expression
使用set debug expression 1命令启用表达式调试模式 设置完后使用p 命令打印变量的值并查看信息。
以下是如下信息的解释:
Dump of expression @ 0x23ee6980, before conversion to prefix form: 在转换为前缀形式之前,表达式的转储:
Language c++, 4 elements, 16 bytes each. 语言为c++,每个元素有4个,每个元素占16个字节。
Index Opcode Hex Value String Value:索引 操作码 十六进制值 字符串值
Expression: temp' 表达式:temp’
Language c++, 4 elements, 16 bytes each.
语言为c++,每个元素有4个,每个元素占16个字节。