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++调试:内存管理/