【问题标题】:Does windows reclaim stack space?Windows 是否回收堆栈空间?
【发布时间】:2011-07-18 13:00:53
【问题描述】:

我正在做一种叫做“堆栈绘画”的技术。确定特定函数使用了多少堆栈空间。

如果我在堆栈上分配 1MB 的项目。然后确定我没有使用堆栈中的任何这些项目。 Windows 会自动解除(释放)那些未使用的页面吗?

我特别想知道 Windows 的 VMM。关于页面是否已提交或不一定已提交但只是保留

换句话说,如果我手动将内存访问到 1MB,Windows 可能会引发访问冲突吗?

【问题讨论】:

  • 好吧,您可能会发生堆栈溢出,所以您来到 stackoverflow.com 很好:)
  • 或者,您可以尝试 BufferOverflow.com。 ;) 嗯...也许 StackOverflow 应该保留该域?

标签: c windows stack


【解决方案1】:

要回答您的第一个问题,没有 Windows 不会取消提交这些页面。随着堆栈增长而提交的任何页面都将保持不变,直到线程终止。

为了回答您的第二个问题,相关字段位于 IMAGE_OPTIONAL_HEADER32 或 IMAGE_OPTIONAL_HEADER64 结构中。它们是 SizeOfStackReserve 和 SizeOfStackCommit。该结构是 PE 的 NT 标头的一部分,该标头又从 MSDOS 标头中引用(在 PE 中以“MZ”作为魔术值的偏移量 0 开始的东西)。

Microsoft 的 link.exe 具有与这两个字段直接相关的“/STACK:reserve[,commit]”开关。

在问题改变后编辑:您只能可靠地访问堆栈的已提交页面和当前保护页面。如果您访问不是保护页面的保留页面,您应该期待一个 AV(如果您访问最后一个保护页面,您将获得 SEH 堆栈溢出异常)。

【讨论】:

  • 如果有人好奇编译器如何为使用保护页面方案的函数“分配”多于一页的堆栈空间,它会使用类似 _chkstk 的东西,它以降序探测每个页面从当前堆栈指针开始排序,以确保访问保护页面并且这些页面由操作系统提交。
【解决方案2】:

您不会删除分配在堆栈上的东西;它会自动回收,因为当您退出当前作用域时,堆栈指针会移回前一个堆栈帧1,因此当前作用域中用于对象的所有内存都会被有效回收。

原则上,所有堆栈都是在应用程序加载到内存时分配的,因此它是一个固定大小的结构,可以反复重用(代码流进出范围);操作系统可能会玩一些巧妙的技巧(通过使用保护页来提交堆栈的上部,这只是在应用程序启动时保留的),但通常这不应该让您担心。

堆栈大小是 PE 标头(可执行文件的标头)的一部分,您可以使用链接器选项设置它。您可以通过窥探内存中加载的 PE 结构来检索加载的可执行文件的此类值(基本上它的HMODULE 是可执行文件在内存中映射的位置);我认为 ImageHelper 库在这项任务中很有用。


  1. 当然,在析构函数运行之后;顺便说一句,FPO 可以在这里稍微改变一下,但概念保持不变。

编辑

换句话说,如果我手动将内存访问到 1MB,Windows 可能会引发访问冲突吗?

如果它已经被提交(即您在堆栈上分配和释放了 1 MB 的对象),我认为它不会发生。

Windows 不会知道堆栈的该部分不再使用。 Windows 可以检测它是否必须提交更多页面,使用保护页面来检测对堆栈上部的访问,但它无法知道这些页面不再被使用。

实际上,它可以在上下文切换时查找堆栈指针,但它会破坏使用堆栈做“聪明”事情的应用程序,而且通常这是一个不值得努力的优化:如果没有内存这些页面仍然可以被调出。

不过,为了安全起见(例如,如果您不知道该分配是否发生),您应该从当前使用的部分向上读取堆栈,因此如果尚未提交向上的页面,您将仍然触摸保护页面,提醒 Windows 为堆栈提交更多页面。

【讨论】:

    猜你喜欢
    • 2015-06-22
    • 2020-12-19
    • 2023-03-17
    • 2021-05-21
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 2016-05-09
    • 2021-09-08
    相关资源
    最近更新 更多