C / C ++中的并行编程,堆栈和堆

那么,如果这感觉像是重复了一些旧问题,我很抱歉,我已经通过tanenbaum回顾了Stack Overflow的几个问题,现代操作系统书,并且仍然要清除我对此的疑问。

首先,我希望能够更详细地阅读任何书籍/资源,以便更好地理解这种结构。 我无法理解这些概念是否在操作系统书籍或编程语言或体系结构书籍中有一般解释。

在问我的问题之前,我会根据关于堆栈/堆的读数列出我的发现

  • 仅包含所有实例变量,动态分配(new / malloc)和全局变量
  • 不再使用数据结构堆,使用更复杂的结构
  • 通过内存位置访问,个人进程负责分配内存
  • 碎片整理和内存分配由操作系统完成(如果是或否,请回答关于谁管理堆,操作系统或运行时环境的问题)
  • 在有权访问其引用的进程中的所有线程之间共享
  • 仅包含所有局部变量。 (在函数调用时推送)
  • 使用实际的堆栈数据结构进行操作
  • 由于连续性,访问速度更快
  • 现在,关于我的几个问题也是如此。

  • 全局变量,他们在哪里分配? (我的观点是它们被分配在堆上,如果是这样,它们什么时候分配,在运行时还是编译时,还有一个问题,这个内存是否可以被清除(如使用delete)?)
  • 堆的结构是什么? 堆是如何组织的(它是由OS还是运行时环境(由C / C ++编译器设置)管理的)。
  • 堆栈是否保存方法和它们的局部变量?
  • 每个应用程序(进程)都有一个单独的堆,但是如果超过堆分配,那么这是否意味着操作系统无法分配更多的内存? (我假设内存不足导致操作系统重新分配以避免碎片)
  • 堆可以从过程中的所有线程访问(我相信这是真的)。 如果是的话,所有的线程都可以访问实例变量,动态分配的变量,全局变量(如果他们有一个引用它)
  • 不同的进程,不能访问彼此堆(即使他们传递的地址)
  • 堆栈溢出崩溃
  • 只有当前线程
  • 当前进程
  • 所有进程
  • 在C / C ++中,内存是否在运行时在堆栈上为函数中的块变量分配(例如,如果代码的子块(例如For循环)创建的新变量是在运行时分配的堆栈(或堆)还是预先分配?)何时被删除(块级作用域,如何维护)。 我的看法是,所有的堆栈添加都是在块开始之前的运行时进行的,只要到达块的末尾,所有添加到该点的元素都将被压入。
  • CPU对堆栈寄存器的支持仅限于一个堆栈指针,可以通过正常访问内存来增加(弹出)和递减(推送)。 (这是真的?)
  • 最后,OS / Runtime环境生成的堆栈和堆结构都存在于主内存上(作为抽象?)
  • 我知道这是很多,而且我似乎很困惑,如果你能指出我正确的方向来清除这些东西,我将不胜感激!


  • 全局变量分配在编译时布置的内存的静态部分。 在进入main之前,这些值在启动期间被初始化。 当然,初始化可以在堆上分配(即,静态分配的std::string将使结构本身位于静态布局的内存中,但它包含的字符串数据在启动期间会分配到堆中)。 这些东西在正常程序关闭期间被删除。 在那之前你不能释放它们,如果你愿意的话,你可能想把值包装在一个指针中,并在程序启动时初始化指针。

  • 堆由分配器库管理。 有一个与C运行时一起提供,但也可以使用tcmalloc或jemalloc等自定义属性,以代替标准分配器。 这些分配器使用系统调用从操作系统获取大量内存,然后在调用malloc时为您提供这些页面的部分内容。 堆的组织有点复杂,并且在分配器之间有所不同,您可以查看它们在网站上的工作方式。

  • 是十岁上下。 尽管你可以使用库函数(如alloca在堆栈上创建一块空间,并将其用于任何你想要的。

  • 每个进程都有一个独立的内存空间,也就是说,它认为它是独一无二的,没有其他进程存在。 一般来说,操作系统会为你提供更多的内存,但是它也可以强制限制(比如linux上的ulimit ),这时它可以拒绝给你更多的内存。 对于操作系统来说,碎片不是问题,因为它会以页面形式提供内存。 然而,在你的过程中碎片可能会导致你的分配器要求更多的页面,即使有空的空间。

  • 是。

  • 是的,但是通常有操作系统特定的方法来创建多进程可以访问的共享内存区域。

  • 堆栈溢出本身不会导致任何事件崩溃,它会导致内存值写入可能包含其他值的地方,从而破坏它。 对损坏的内存进行处理会导致崩溃。 当你的进程访问未映射的内存时(见下面的注释),它会崩溃,不仅仅是一个线程,而是整个过程。 它不会影响其他进程,因为它们的内存空间是孤立的。 (在Windows 95等旧操作系统中,所有进程共享相同内存空间的情况都不是这样)。

  • 在C ++中,堆栈分配的对象在块被输入时创建,并在块被退出时被销毁。 尽管堆叠上的实际空间可能不太精确,但是建造和破坏将发生在这些特定点上。

  • x86进程上的堆栈指针可以任意操作。 编译器通常会生成简单地将大量空间添加到堆栈指针的代码,然后为堆栈中的值设置内存,而不是执行一堆推式操作。

  • 进程的堆栈和堆都位于相同的内存空间中。

  • 内存如何组织的概述可能会有所帮助:

  • 你拥有内核看到的物理内存。
  • 当进程请求时,内核会将物理内存页面映射到虚拟内存页面。
  • 一个进程在它自己的虚拟内存空间中运行,不知道系统上的其他进程。
  • 当一个进程启动时,它将可执行文件的部分(代码,全局变量等)放入这些虚拟内存页面中的一部分。
  • 分配器请求进程中的页面以满足malloc调用,此内存构成堆。
  • 当线程启动时(或进程的初始线程),它会向操作系统请求构成堆栈的几个页面。 (你也可以问你的堆分配器,并使用它给你的空间作为堆栈)。
  • 程序运行时,它可以自由访问其地址空间,堆栈,堆栈等所有内存。
  • 当您尝试访问未映射的内存空间区域时,程序崩溃。 (更具体地说,你从操作系统得到一个信号,你可以选择处理这个信号)。
  • 堆栈溢出往往会导致程序访问这些未映射的区域,这就是堆栈溢出会导致程序崩溃的原因。

  • 全局变量分配的位置实际上取决于系统。 有些系统会将它们静态放置在二进制文件中,有些系统会将它们分配到堆中,有些系统会将它们分配到堆栈中。 如果一个全局变量是一个指针,你可以delete它指向的值,但是否则无法清除该内存。 当应用程序退出时,将自动调用全局变量的析构函数(嗯,也许不用SIGTERM)
  • 我并不积极,但我认为它是由操作系统,特别是内核管理的。
  • 是的,只有某一点。 例如,你不能做无限递归,因为数值会(没有双关意图)叠加起来。 你会得到一个,等待它,堆栈溢出(AHH,就是这样,他说了!)
  • 有些操作系统可能会通过单独的进程强制堆栈大小限制,但通常如果您未能分配内存,这是因为没有剩余内存。
  • 所有的线程共享一个共同的堆,所以是的,他们都可以访问全局变量,动态分配等。
  • 通常是正确的,但在一些真正的骨架架构上,这可能不是真的。 大多数情况下,操作系统在虚拟表的上下文中执行进程,因此您正在使用的指针值实际上指向的内存地址与其显示的内存地址不同。
  • 当前进程,如果按进程进行,则意味着OS级进程。
  • 我假设这是正确的,但我不知道我自己。
  • 这是我的驾驶室。
  • 是的,有点。 正如我之前提到的,大多数操作系统使用vtables将进程指针映射到主内存。 另外,请考虑分页到磁盘(交换)
  • 链接地址: http://www.djcxy.com/p/14507.html

    上一篇: Concurrent Programming, Stacks and Heaps in C/C++

    下一篇: Dynamically switching between stack and heap