我目前正在学习C ++中的动态内存,并且在尝试完全理解和理解程序内存中的内存段时发现了许多麻烦。
所以我们有4个内存段:Stack,Heap,Data和Code。
首先,我想看看我是否掌握了它的基础
- Stack:一个像堆栈一样被管理的内存段 进入范围后,您在该范围内为该范围分配的内存有限,其中包含有关该范围的信息 (变量等)
- Heap:一个无限制的动态内存段,当您在该段中分配内存时,它将不会被删除,因为您退出所使用的代码或函数的范围,它需要是被你或gc删除(如果它不再可用)
- 代码:包含需要由CPU执行的代码的内存段
- 数据:包含变量信息的内存段(int x - x代表内存单元格0x0FA20F)
我的第一个问题是,我做对了吗?我真的不确定......
如果我没有把它弄好我的问题是:
每个内存段用于什么?
关于变量的内存段信息,例如,
int x
- x代表内存单元0x0FA20F
位于?
使用递归时,从内部调用函数时 函数仍然有代码留在该函数中执行,即 代码保存在人们称之为堆栈的内容中,代码是什么? 常规的Stack段?如果是这样意味着在堆栈内 存储需要在当前范围内执行的常规代码行? 那么用于?
如果有人能够组织我脑海中现在的混乱,并且在向我解释每个记忆片段在提到我的问题时完全做了什么的话,我会喜欢它。
答案 0 :(得分:5)
我的第一个问题是,我做对了吗?我真的不确定......
您似乎在讨论实模式 x86 arch时的段。现在一切都不一样了。
每个内存段用于什么?
现在你应该考虑访问模式。 “代码”是您可以“阅读”和“执行”的内存页面; '数据'='读'和'写'等。
关于变量的内存段信息,例如,int x - x代表存储单元0x0FA20F的位置?
无处。命名变量仅存在于源文件(和中间目标代码文件)中。实际代码只有“数字”地址。
当使用递归时,当你从函数中调用一个函数并且仍然有代码留在该函数中执行时,该代码会被保存在人们称之为Stack的内容中,该内容是什么?
'Code'是只读的,除了它所在的位置之外,它不能保存在任何地方。保存的是本地(即堆栈)变量和返回地址。两者都保存在堆栈中。
答案 1 :(得分:4)
你关闭了,但并不完全。你指的是一个很老的模型,类似于实模式的x86内存。但是,让我们一起运行,并尝试消除一些困惑......
首先,在讨论内存模型时,C ++(由标准指定)不会对诸如 stack 或 heap 等术语进行任何引用。这些是实施的细节。要继续,请假设您正在谈论典型的x86(32位或64位)PC实现。
C ++本身定义了以下storage durations:
new
分配,通过delete
解除分配。该变量一直存在,直到被删除,并将在您的实现中的堆上分配。对于零初始化变量,还有一个 bss 段。
每个函数调用都有自己的堆栈帧,其中包括具有自动存储持续时间的所有变量,以及函数的参数,返回值的空间以及调用函数状态的存储副本。当函数返回时,将恢复此状态,以便您可以从上次停止的位置继续。该状态的一部分是指令指针,它是指向要执行的下一条指令的指针。指令序列本身始终位于代码段中;它不会被复制到堆栈中。
这是一种简化,对于大多数用途,您不需要知道超出存储持续时间标准定义的任何内容;其余的是实施细节!
[注意:现代用法倾向于考虑内存访问权限。代码将加载到只读和可执行的内存页面中,而数据(包括堆栈)将位于读写页面中理想地标记为不可执行。除了堆栈/堆之外,任何进一步的区别都是毫无意义的。]
答案 2 :(得分:2)
嗯,大多数情况下,我们实际上有5个段:堆栈,堆,文本(代码),数据,BSS(按段开始块 - 历史名称)。
澄清数据和您错过的数据 - BSS:
使用递归时,程序代码存在于Text(代码)中,但函数的局部变量,一些函数参数(取决于体系结构)和返回值(取决于体系结构)都存在于堆栈中。是的,那是在常规堆栈段内。
在Linux上,您可以在可执行文件上使用size命令为您提供大小的报告:
[root@boran ~]# size /bin/bash
text data bss dec hex filename
902580 35984 22920 961484 eabcc /bin/bash
当我想启动我的bash解释器时,操作系统将分配文本部分并将代码复制到它。它将分配数据部分并将数据复制到它,但它将分配BSS的大小并将其归零。之后,每个程序都会获得一个堆栈大小,操作系统会动态地将它提供给你,以便跟上。堆是你通过调用系统调用手动分配的东西。堆和堆栈大小都可以限制。最后,通过跳转到代码部分中的地址来调用程序。