首页 文章

堆和堆栈存储器如何管理,实现,分配[重复]

提问于
浏览
2

可能重复:堆和堆栈内存是如何管理,实现,分配的?堆栈,静态和堆中的C

在C / C中,我们可以在堆栈或堆上存储变量,函数,成员函数,类的实例 .

每个如何实施?如何管理(高级别)? gcc是否预先分配了一大块内存用于堆栈和堆,然后根据请求发送?原始内存来自RAM吗?

可以在堆而不是堆栈上分配函数吗?

--Clarification--

我真的在询问堆和堆栈存储器的实现和管理 . After reading referenced question,我没有发现任何解决这个问题的内容......感谢您的链接

1 回答

  • 10

    我想你的问题可以很容易地写出关于操作系统的书的一些章节 . 我建议你阅读Tanenbaum:现代操作系统 .

    堆和堆栈的主要区别,一个是每个进程项,另一个是每个线程项 . 最初,当程序启动时,它会获得一些最小的堆和一些堆栈段 . 堆增长,堆栈是静态的(对于每个线程) . 如果你编写一个不终止的递归函数(无限递归)你将得到堆栈溢出;)任何函数调用在堆栈段上都有一个堆栈帧,当函数离开时,堆栈被展开并且框架可以自由使用下一个功能 . 堆栈是一种连续的线性结构 . 在Linux上,您可以通过环境变量为进程配置堆栈段大小 . 在Windows上(至少使用MS Visual C),您可以传递具有堆栈段大小的链接器标志 . 在编译时分配一些大数组时也可以产生堆栈溢出:

    char test[1000000];
    

    堆是一个不同的故事 . 当进程启动时,堆大小是一些默认值,并且可能因操作系统或操作系统上使用的配置而异(例如,在Windows上,默认情况下它是2MB,据我所知) . 此外,如果您需要更多堆,为变量等分配更多空间,它将会增长 . 如果程序没有释放堆内存,它就会耗尽它(或堆空间) . 堆实现有不同的数据结构,其中一些是二叉树衍生物,有些不是例如 . 斐波纳契堆(树木的福雷斯特) . 您可以阅读有关如何编写内存分配器的一些文章等 . 必须优化这些数据结构,以便在需要取消分配已分配的块时查找堆节点,或者在需要新的堆空间时附加(查找空闲块) .

    32位操作系统上的每个进程都有4GB的虚拟地址空间 . 可以想象,没有那么多的RAM可以满足所有具有4GB虚拟地址空间的进程 . 操作系统内存按页面组织,不再需要或过期时可以交换为HD . 这就是分页发挥作用的地方 . 一切都映射到页面:堆栈或不断增长的堆的进程 . 由于它动态增长的堆结构,它可以放在多个页面上 . 这就是为什么堆访问可能非常昂贵的原因,因为如果页面不在内存中,则会发生页面错误,并且操作系统必须从磁盘加载页面(这可能会更慢) . 正在执行的线程的堆栈帧位于处理器高速缓存中,这比RAM快得多 .

    不同的堆类型是可能的,可能存在对于小型对象或在多线程环境中非常有效的堆非常快的堆 . Alexandrescu在“Modern C Design”中描述了如何开发小对象分配器和管理小对象的堆 . 这个实现可以在他的Loki C库中找到 . 一些嵌入式系统提供物理上不同的内存区域,其中可以在顶部实现不同的堆类型 . 如果要打败编译器,编写自己的分配器(堆管理器等)是一项艰巨的任务 .

    问候,
    Ovanes

相关问题