什么是堆栈不平衡?

时间:2011-07-21 16:32:30

标签: memory-management f# stack terminology

阅读本文F# Versus Mathematics: Part One - Getting Started with BLAS and LAPACK后,我偶然发现stack imbalance段中的A Warning, Perhaps an Omen一词。

googled并在SO上进行搜索,但只能找到人们在堆栈不平衡时遇到困难而且没有一般性的解释。

奖金问题: 它只影响f#还是C,C ++,Python,Java等中的一般问题?

P.S。如有必要,请更改问题的标签

2 个答案:

答案 0 :(得分:9)

当用于跟踪被调用函数,参数和返回值的数据结构被破坏或未对齐时,会发生堆栈不平衡。

大多数情况下,堆栈是一个内存指针,用于存储当前函数调用退出调用者时控件将恢复的地址。这有不同的变体,有时函数的参数也会附加到堆栈,以及返回值。这里最重要的是调用者和被调用者应该同意如何在被调用者退出时将其恢复到先前状态。此协议通常称为呼叫约定

在.NET中,堆栈不平衡是纯托管代码中难得存在的问题。但是,在调用非托管代码时,这可能是一个常见的问题,因为您需要告诉编译器应该如何调用该方法,这意味着应该如何根据调用约定清理堆栈。

在Windows上,有一些标准调用约定涵盖了大量的调用案例。

stdcall - Callee将在退出时修复堆栈 fastcall - 除了返回地址之外,可能不需要修复堆栈,而是使用CPU寄存器来传递参数。
cdecl - 调用者将在被调用函数返回后修复堆栈。

此处提供正式参考:Argument Passing and Naming Conventions @ MSDN

这也是有趣的:X86 calling convention list @ Wikipedia

在给定的开发域中,这往往不是问题。每种语言通常都有一个隐含在所有方法调用中的约定。 C / C ++使用相同的约定来调用C / C ++调用,Python用于其他Python调用等。当跨域时,如果一个域不使用相同的域,它可能会成为一个问题。也许在Windows中最常见的是,使用“C”样式声明(cdecl)导出的函数可能会在调用时导致不平衡堆栈(或更糟糕),就好像它有一个stdcall约定,这是WINAPI(windows系统)调用识别的方法。

答案 1 :(得分:4)

我们前几天才看到这个(用c#和c ++编组)

我建议您使用MSDN页面中的文字:

  

pInvokeStackImbalance管理调试助手(MDA)是   当CLR检测到平台后的堆栈深度时激活   给定调用时,invoke调用与预期的堆栈深度不匹配   DllImportAttribute属性中指定的约定以及   管理签名中的参数声明。

我意识到这是针对特定的编译器警告,但页面提供了有关堆栈不平衡是什么,导致什么,症状是什么以及如何解决它的一些信息。正如Daniel所说,这通常是由于托管和非托管的签名不匹配。

希望这有帮助。