C++:通过打印地址了解内存布局是如何工作的?

问题描述 投票:0回答:1

我想了解 C/C++ 程序如何分配内存。我想看看它是如何工作的,所以想到打印出本地(堆栈)和动态(堆)分配的变量的地址。这个想法是通过检查地址来构建内存(堆栈和堆)的逻辑图像。

#include <iostream>

void func() {
    int x = 10; // local(func) variable (stack allocated)
    std::cout << "func: local x @" << (void *)&x
              << " (" << sizeof(x) << ")" << std::endl;
}

int main() {
    int x = 10; // local(main) variable (stack allocated)
    std::cout << "main: local x @" << (void *)&x
              << " (" << sizeof(x) << ")" << std::endl;

    int y[4]; // local(main) array of ints (stack allocated)
    for (int i = 0; i < sizeof(y)/sizeof(y[0]); i++) {
        std::cout << "main: local y[" << i << "] @" << (void *)&y[i] 
                  << " (" << sizeof(y[i]) << ")" << std::endl;
    }
    func();
    int *z = new int(10);
    std::cout << "main: heap z @" << (void *)z // heap allocated variable
              << " (" << sizeof(*z) << ") " << std::endl;
    std::cout << "main: local z @" << (void **)&z  // local(main) pointer (stack allocated)
              << " (" << sizeof(z) << ") " << std::endl;
    delete z;
}

但是我记得程序不直接使用物理地址,而是使用虚拟地址。只是一些细节:我有一个x86_64机器(我相信堆栈向下增长)运行Linux(Mint)和48位虚拟地址空间.

$ lscpu
Address sizes:                   39 bits physical, 48 bits virtual

,所以我在程序输出中得到了预期的 48 位(6 字节)地址,按地址降序排列括号中的字节大小):

$ ./a.out | sort -k4 -r | column -t
    main:  local  y[3]  @0x7ffe7d0b001c  (4)
    main:  local  y[2]  @0x7ffe7d0b0018  (4)
    main:  local  y[1]  @0x7ffe7d0b0014  (4)
    main:  local  y[0]  @0x7ffe7d0b0010  (4)
    main:  local  z     @0x7ffe7d0b0008  (8)
    main:  local  x     @0x7ffe7d0b0000  (4)
    func:  local  x     @0x7ffe7d0affe4  (4)
    main:  heap   z     @0x5648f749dec0  (4)

基于上面的输出,我想出了下面的内存图像(主要是堆栈),显示为 4 字节的

                    Stack
                +-----------+ 0x7ffe7d0b001c 
       main:    |   y[3]    | 
                +-----------+ 0x7ffe7d0b0018 
                |   y[2]    | 
                +-----------+ 0x7ffe7d0b0014 
                |   y[1]    | 
                +-----------+ 0x7ffe7d0b0010 
                |   y[0]    | 
                +-----------+ 
                |     ?     |
                +-----------+ 0x7ffe7d0b0008 
                |           | 
                +     z     +
                |           |
                +-----------+ 0x7ffe7d0b0000 
                |     x     | 
                +-----------+ 0x7ffe7d0afffc
                |     ?     |
                +-----------+ 0x7ffe7d0afff8
                |     ?     |
                +-----------+ 0x7ffe7d0afff4
                |     ?     |
                +-----------+ 0x7ffe7d0afff0
                |     ?     |
                +-----------+ 0x7ffe7d0affec
                |     ?     |
                +-----------+ 0x7ffe7d0affe8
                |     ?     |
                +-----------+ 0x7ffe7d0affe4 
      func:     |     x     | 
                +-----------+
                    ...

                    ...
                +-----------+ 
                |  new int  | 
                +-----------+ 0x5648f749dec0 
                    Heap

正如您在

?
s 中看到的那样,我无法解释
main
的堆栈帧中的某些内存。我没有分配比显示的更多的局部变量,所以这个内存去哪里了?话虽这么说,我采取的方法是解决这个问题的好方法吗? 我看到的虚拟地址实际上可以用来在程序执行期间绘制准确的内存图片吗? 我确信为此目的存在更专业的分析工具,但我进行此练习的目的是查看有多少信息我可以从一个基本程序中收集到信息。欢迎任何建议。

c++ memory heap-memory virtual-memory stack-memory
1个回答
0
投票

要查看用户空间的布局,您通常会让链接器生成详细的链接映射文件。这样做的过程取决于您使用的链接器。您使用的方法可能会产生访问冲突。

您还可以使用系统服务来获取有关内存使用情况的信息。

对于系统空间的布局,您要么必须使用操作系统的系统文档,要么必须成为内核模式突击队员。

你正在尝试做的事情并不是很有用,因为你并没有真正看到这样一个程序中的内存分配。在内存分配方面,“栈”和“堆”没有区别。唯一的区别是它们的使用方式。堆栈和堆看起来一样。

在系统中,您将拥有内存 只读/执行代码 只读/不执行静态数据 读/写/执行 通常避免 read/Write/Noexecute 栈、堆、静态变量

© www.soinside.com 2019 - 2024. All rights reserved.