博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++内存分配
阅读量:3957 次
发布时间:2019-05-24

本文共 1832 字,大约阅读时间需要 6 分钟。

参考网址:

内存分配

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

动态链接库

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

转载地址:http://fxxzi.baihongyu.com/

你可能感兴趣的文章
[无线] Android 系统开发学习杂记
查看>>
[无线] 浅析当代 LBS 技术
查看>>
[杂感] 缅怀乔布斯
查看>>
[无线] 让Android支持cmwap上网
查看>>
[教程] Android PHP 最佳实践视频教程
查看>>
[无线] AndroidManifest.xml配置文件详解
查看>>
[无线] 2012 智能手机市场分析
查看>>
[移动] Android推送方案分析(MQTT/XMPP/GCM)
查看>>
[移动] Mosquitto简要教程(安装/使用/测试)
查看>>
[HTML5] 关于HTML5(WebGL)的那点事
查看>>
自我反思
查看>>
初识网络编程
查看>>
很像动态规划的贪心
查看>>
东北赛选拔教训
查看>>
hash
查看>>
涨姿势了:求两个分子的最大公倍数
查看>>
快速幂
查看>>
vector.reserve and resize &&vector与map结合
查看>>
最短路
查看>>
最长公共子序列
查看>>