【问题标题】:Measuring Stack Space测量堆栈空间
【发布时间】:2021-12-31 12:57:40
【问题描述】:

最近面试英特尔,被问到这个问题

在不使用任务管理器的情况下如何测量堆栈空间, 当应用程序在计算机上运行时?写一个算法,如果 可能

我不知道如何处理这个问题。我什至在互联网上搜索过,但没有找到任何相关的答案。因此,我正在寻求 StackOverflow 人员的帮助,以帮助我理解问题以及如何解决。

【问题讨论】:

  • 你的意思是汇编语言吗?或者在 Linux 之类的操作系统下,您可以阅读 /proc/self/maps? (或进行mmap(MAP_FIXED_NOREPLACE) 系统调用,直到找到尚未映射的页面)。

标签: algorithm memory memory-management intel stack-memory


【解决方案1】:

首先,我注意到这里很大程度上依赖于 C++ 最常见的实现方式。我将要描述的内容几乎总是适用于 Intel x86 或任何远程类似设备上的任何实际实现——但它可能会在 IBM 大型机或早期 Cray(两者都不真正支持堆栈在硬件中)。就此而言,它并不能真正保证在任何东西上工作 - 但它会在大多数当前硬件上按预期工作(尤其是:几乎任何带有 Intel x86 处理器的东西)。

这很大程度上取决于我们是尝试从内部程序还是从外部(即,从另一个程序)执行此操作。

程序内部

如果我们是从程序内部进行的,我们可以从 main 开始,如下所示:

char *stack_bottom;

int main() { 
    int a;
    stack_bottom = &a;

这为我们提供了一个位于堆栈底部的地址(嗯,从技术上讲,并不完全是底部,但无论如何都非常接近它)。

然后在我们想知道当前堆栈深度的任何给定点,我们可以调用一个类似这样的函数:

ptrdiff_t stack_size() { 
    char a;
    return abs(stack_bottom - &a);
}

这会在堆栈顶部创建一个变量,然后将两者相减以获得大小。堆栈通常在内存中向下增长,因此堆栈的“顶部”通常位于比顶部低的地址。由于我们只关心差异的大小,因此我们采用差异的绝对值(尽管如果我们知道堆栈增长的方向,我们可以避免这种情况)。

Windows 特定

由于这似乎是针对 Windows,我们可以使用 VirtualQuery 来获取有关堆栈内存的类似信息。

计划之外

从程序的“外部”来看,基本的想法几乎相同:找到栈底,找到栈顶,减去找到大小。但是,很有可能我们必须找到不同的顶部和底部。

不过,这往往会进入更多特定于操作系统的领域。例如,在 Windows 上,您可能会使用 StackWalk64 遍历堆栈并告诉您顶部和底部的地址。在 Linux 上,您通常会改用 backtrace。在其他一些操作系统上,您很有可能会使用具有其他名称的函数,以其他格式生成数据。但大多数都会按照相同的一般顺序提供一些东西。

一旦我们得到了栈顶和栈底的地址,我们又回到了几乎相同的情况:将栈顶和栈底的地址相减得到大小。

使用调试器

另一种可能性是在调试器下运行程序。虽然我们通常希望在进行任何调试之前运行启动代码,但在这种情况下,我们可以只加载程序,并查看 ESP 寄存器以查看堆栈从哪里开始。然后当我们想找到我们打破的堆栈大小时,获取 ESP 中的值并(当然)减去以获得大小。

警告

如果您想了解技术,我在第一个中展示的内容不会正好是堆栈的整个大小。通常有一些启动例程执行诸如检索环境变量和命令行、按预期格式化它们、调用全局对象的构造函数等,它们在main 之前运行。所以有一些空间不会被捕获。但是它缺少的是一个很小的(通常是固定的)数量,所以通常我们根本不会关心它。但是如果我们真的需要知道确切的数量,我们可以(例如)查看启动的源代码来弄清楚。

【讨论】:

  • 非常感谢您的回答和见解.. :)
  • 在外部操作系统下,在 Linux 上,您可以阅读 /proc/<PID>/smaps 并查看堆栈映射的已分配大小和“脏”大小。这将告诉您堆栈实际消耗了多少内存页,这取决于堆栈曾经达到的“高水位线”,而不是当前的堆栈深度。
  • 请注意,stack_bottom - &a 在 ISO C 中是未定义的行为;减去不是从同一个对象派生的两个地址。它确实适用于具有平面内存模型(例如现代 x86)的机器的主流 C 实现,所以我认为它至少是 GCC 等编译器下事实上定义的行为。转换为 intptr_tuintptr_t first 会更安全地避开可能的 UB,因为我们知道我们的目标是具有平面内存模型的机器;见Does C have an equivalent of std::less from C++?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-04
相关资源
最近更新 更多