C++内存分配

参考网址:https://blog.youkuaiyun.com/dongtuoc/article/details/79132137

内存分配

c++运行时,内存主要包括几个部分:

  • 动态链接库(内存映射区)
  • 全局区
  • 代码区
  • (文字常量区)

如下图所示:
C++内存分配
注:对于这个图,我在网上搜到的图,虚拟地址全都是这样的,然而在我实际使用C++程序测试时,返回的地址指针却并不符合,这里我不太懂是为什么,但是他们的上下关系是对的,比如常量区确实在代码区的高地址方向。如果有大佬知道,还望不吝赐教。

堆中存储由程序员用new和malloc等函数分配的变量。空间最大,以链表形式管理,物理空间不连续,由低地址向上扩展。需要手动释放,不然容易内存泄漏。每个进程有一个堆。每次申请堆内存时,从小到大遍历链表,直到找到大于等于申请空间的内存,然后取出其中等于申请空间的内存,将剩余内存返回堆中。

栈存储非静态局部变量、函数参数、以及一些程序调用时的寄存器值。空间小,容易溢出,物理空间连续,由高地址向下扩展。每个线程都有自己的栈。

比如对于如下程序:

void func(int x, int y)
{
    x = 5;
    int z = 12;
    int w = 345;

    std::cout << "In func(). x = " << x
        << ", variable in stack: " << z << ", " << w << std::endl;
}

int main(void)
{
    int x = 90, y = 26;
    func(x, y);
    return 0;
} 

其中,x、y、z、w这些变量就是存储在栈上的。
另外在进行函数调用的时候,还会对栈进行一系列操作,过程如下:

  1. 首先将函数调用的参数从左向右依次拷贝,并将拷贝入栈;
  2. 然后记录函数返回时跳转的地址(即main函数中调用func的位置,对应寄存器eip的值);
  3. 栈底指针ebp入栈,然后将ebp指向esp,转到新函数的栈;
  4. 然后为新函数的栈变量预留一部分空间;
  5. 然后将ebx(基地址寄存器),esi(源索引寄存器),edi(目标索引寄存器)入栈。(这里ebx,esi,edi为何需要入栈,我现在还不太懂,似乎和回调函数有关?如有大神知道,还望指教)

函数调用结束后同样会做一些处理,过程如下:

  1. 首先将ebx、esi、edi出栈;
  2. 然后释放栈变量的空间;
  3. 然后将ebp出栈,赋值给ebp寄存器,从而回到main函数的调用栈;
  4. 将eip值出栈,返回main函数;
  5. 最后将参数值出栈

栈的变化总体如下图所示:
函数调用时栈的变化
这样的过程也解释了,为什么函数内部的对参数的改变,当函数调用结束后,外部并不能看到,因为改变的是栈中参数的拷贝,而不是本来的值。比如上图中,在func函数中改变了参数x的值,只是改变了栈中的拷贝,当返回main函数的调用栈时,main函数看到的仍然是90,而不是5。

另外,所谓的出栈也只是改变了esp寄存器,栈中实际内存的数据并没有进行任何修改,因此在合适的时机(调用新函数前),其实仍然是能看到这些数据的,比如在func函数中将w的地址作为返回值返回,然后在main函数中马上查看对应地址的值,仍然是能看到345的。但是一旦调用了新函数,这个值就可能被覆盖掉。因此C++并不推荐返回栈变量的地址。

最后关于函数的返回值,如果小于8字节(32位系统则是4字节,主要取决于寄存器大小),会被存放在EAX寄存器中,然而如果是更大的数据,那么具体会被存放在哪里我不太了解,但是会将其地址存放在EAX寄存器中。

全局区

全局区存储全局变量和静态变量。

代码区

代码区存放运行代码。

常量区

我现在只了解,文字常量存储在该区域。比如:

const char *p = "hello world!";

其中,p指向的地址就在常量区,即“hello world!”这段文字常量即存储在文字常量区。

对于常量:
最后,对于常量,经验证,内置类型的常量,会被vs编译器直接转化为立即数进行使用。因此可以理解为实际存在了代码区。
但是一旦对其进行取地址,那么编译器会为其在栈中分配地址。然而在实际调用常量时,并不会访问该地址,仍然使用立即数。但通过指针访问的话,会访问该地址。因此会出现,通过指针强行修改常量的值后,指针明明指向常量的地址,但指针读到的数值与常量不一样的情况。

动态链接库

其实应该叫内存映射区,因为这里不仅有动态链接库,共享内存也会映射到这个区域。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值