C++调试:内存管理
正文
本文将会通过一个例子,通过 nm、lldb 工具查看 ELF 文件的内存管理:
1 | |
编译,通过 nm 打印符号信息表( nm 只能打印出全局符号,因为局部变量不会出现在全局符号表中。nm 主的用途是列出全局符号,比如全局变量、静态变量以及函数名等。局部变量的信息通常在编译时被分配到栈上,并不包含在全局符号表中):
1 | |
可以看到 _g_var、_gp_var 都位于.sbss ,尽管一个初始化一个未初始化,但是C++中不再区分初始化和未初始化的全局变量、静态变量的存储区,因此它们显示都是 S。以下是更详细的解释:
在 nm 命令输出中,S 和 B 都指示变量未初始化,但它们并不相同,也不属于同一个类别。每个符号都独立表示不同的存储特性或区段。这里是更详细的区分:
b/B (大写):
B表示变量位于.bss段,这是专门用于存储未初始化的全局变量和静态变量的内存区段。这些变量在程序启动时自动被初始化为零。
s/S (大写):
S通常用于指示小型未初始化数据段,如.sbss。.sbss是.bss段的一个小段,用于存储较小的未初始化变量,以优化内存的使用。S并不直接属于B,但它表示的是一个与B类似的概念,专门针对小型数据。
简而言之,S 和 B 都涉及未初始化的数据,但它们代表的是不同的内存区段。S 不属于 B,但两者都用于未初始化数据的存储,只是大小和存储优化方面有所区别。因此,在处理大型和小型未初始化数据时,编译器和链接器可能会选择将它们分别放在 .bss 或 .sbss 段中。
接着用 lldb 进行调试,lldb 可以查看 main 中的局部符号:
1 | |
这些信息足够查看以及推断:
| 局部符号 | 地址 | section |
|---|---|---|
| var | 0x000000016fdfeff8 | 栈区 |
| p_var | 0x000000016fdfeff0 | 栈区 |
| arr | 0x000000016fdfefec | 栈区 |
| p_var1 | 0x000000016fdfefe0 | 栈区 |
| s_var | 0x0000000100008028 | .bss |
| “123456” | 0x0000000100003fb0 | 常量区 |
之所以推断 0x0000000100003fb0 位于常量区,依据是上面的信息0000000100003f0c T _main,.text 接下来就是 .rodata,地址很近。
C++调试:内存管理
http://blog.luliang.online/2024/05/16/C++调试:内存管理/