【问题标题】:Why can stack usage take place without prior allocating the memory?为什么可以在没有事先分配内存的情况下使用堆栈?
【发布时间】:2012-07-21 19:15:08
【问题描述】:

进程的虚拟地址空间以进程的textdatabss 段开头。放置此堆分配后,堆会向更大的内存地址增长。但是,在使用堆的一部分之前,必须分配内存块(valloc 等),否则会发生(或应该发生)segfault

堆栈从虚拟地址空间中的初始大地址向更小的值增长。据我所知,这无需虚拟内存分配即可工作。如果在堆的情况下这是不可能的,如何在没有事先分配内存的情况下使用堆栈? (它是相同的线性虚拟地址空间。)

据我所知alloca 的实现方式与sub esp, <size> 相同。但是堆栈使用的虚拟地址空间区域必须在此之前以某种方式分配,对吧?

【问题讨论】:

    标签: linux memory stack


    【解决方案1】:

    确实在某种程度上发生了段错误。这是一种“惰性”优化。操作系统会尽可能多地作弊,只要差异不可从外部观察到。

    但是,陷阱不会像正常的段错误那样导致生成信号(默认情况下会终止进程)。相反,操作系统会验​​证允许的线程大小没有超出,然后从零池中拉出一个新页面。

    在 Windows 下,该机制被称为“保护页面”,我不知道在 Linux 下有类似的命名。无论哪种方式,从技术上讲,保护页面只不过是一个写保护页面(或不存在的页面),操作系统将其记住为“特殊”,因此当它被触摸时可能会发生一些特定的操作。

    这也与动态分配(malloc,调用sbrk)的工作方式非常相似。当您分配内存时,只要您不访问分配的内存,就不会发生太多事情。唯一发生的事情是操作系统“记住”您增加了数据段。
    如果现在发生故障,操作系统将创建页面,或者分别从零池中拉取它,并假装它一直在那里。你永远不知道它以前不存在。

    【讨论】:

    • 好的,这就解释了。很好的答案!
    • Linux 不使用保护页面。故障处理程序只是通过算术检查故障地址是否位于可以从当前堆栈指针到达的区域中,即:address + 65536 + 32 * sizeof(unsigned long) < regs->sp,它允许enter $65535,$31 工作。见arch/x86/mm/fault.c:do_page_fault()
    猜你喜欢
    • 2011-01-20
    • 1970-01-01
    • 2020-04-25
    • 2019-12-07
    • 1970-01-01
    • 2014-12-19
    • 2012-02-26
    • 1970-01-01
    • 2016-08-30
    相关资源
    最近更新 更多