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