我读到当程序进行函数调用时,被调用函数必须知道如何返回其调用者.
我的问题是:被调用函数如何知道如何返回其调用者?是否有通过编译器在幕后工作的机制?
假设我有一个函数,根据某些运行时条件创建昂贵的自动对象或创建便宜的自动对象:
void foo() {
if (runtimeCondition) {
int x = 0;
} else {
SuperLargeObject y;
}
}
Run Code Online (Sandbox Code Playgroud)
当编译器为此函数的堆栈帧分配内存时,它是否会分配足够的内存来存储SuperLargeObject,并且如果导致 的条件为int真,则额外的内存将不会被使用?或者它会以其他方式分配内存吗?
使用反射时,可以使用System.Diagnostics.StackTrace获取调用堆栈(除了它可以是由JIT优化引起的粗略近似)并检查包含的StackFrame对象.
如何获取对堆栈帧中的方法正在执行的对象(this-pointer)的引用?
我知道我可以通过在堆栈框架对象上调用GetMethod()来获取MethodBase,但我正在寻找的东西是GetObject()(如果方法是静态的,它会自然地返回null).看起来堆栈帧对象只能查询静态确定的信息,例如方法信息,原始文件等.
VS调试器知道(虽然它可能使用另一种获取调用堆栈跟踪的方法),因为可以双击调用堆栈窗口中的任何堆栈帧并查看本地和类字段的值.
编辑:澄清:我想要调用该方法的对象实例.即:如果在调用堆栈的某个地方的对象实例A上调用方法Foo(),并且它级联到我执行堆栈跟踪的方法,我想从我执行堆栈跟踪的位置获取对A的引用.(不是方法库的声明类型)
在Java中,有没有办法查看完整的,未截断的堆栈跟踪(例如,通过增加记录的帧数),或以其他方式获取堆栈跟踪的底部?通常情况下,堆栈跟踪在1024帧的情况下从顶部被截断,但是对于堆栈溢出问题,这实际上是毫无价值的,因为您确实需要查看是谁进行了触发递归的调用,靠近底部.更好的是在堆栈中间截断,但显然Sun的JVM不够聪明,无法做到这一点.
甚至可能是一些特殊的Sun特定标志?我尝试将堆栈大小减小到允许的最小值(-Xss1000),但仍然超过1024帧.
就我而言,我正在尝试调试Hadoop映射器中发生的堆栈溢出,但仅限于在非常大的输入上运行时.我假设问题来了,因为递归操作(Scala foldRight)正在一个非常大的链表上完成,我需要非递归地重写它...但我需要知道是谁调用了它foldRight.这是一个直接和间接在很多地方调用的基本例程,我正在使用很多很多代码,所以这是非常不明显的.
作为回答另一个问题的一部分,我想表明gcc(-O3)的疯狂优化级别基本上会删除任何未在main中使用的变量.代码是:
#include <stdio.h>
int main (void) {
char bing[71];
int x = 7;
bing[0] = 11;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
和gcc -O3输出是:
.file "qq.c"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
pushl %ebp
xorl %eax, %eax
movl %esp, %ebp
popl %ebp
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
现在我可以看到它删除了局部变量,但那里仍有相当多的浪费.在我看来,整个:
pushl %ebp
xorl %eax, %eax
movl %esp, %ebp
popl %ebp
ret
Run Code Online (Sandbox Code Playgroud)
部分可以用更简单的替换:
xorl %eax, %eax
ret
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么gcc不执行此优化?我知道这样可以节省很多,main …
在我之前的问题中,我想在堆栈中转储所有变量(从当前和所有前一帧),这里可以看到:有没有办法在运行时检查C#中的堆栈变量?
我被建议手动拦截调用或使用像PostSharp这样的AOP框架来简化这样的任务.我查看了PostSharp,并且拦截参数不包含当前堆栈帧中的变量.我想知道是否有一种简单的方法可以自动获取当前堆栈帧中的所有局部变量.我想我可以执行代码分析并生成将所有这些值复制到集合中的代码,但也许有一个内置机制来完成它.
在此先感谢您的任何建议.
编辑:我应该详细说明为什么我要这样做.我希望能够在方法中间暂停执行.如果我有堆栈的内容,我可以稍后恢复执行,甚至序列化它并在另一台机器上继续(假设它是相对简单的代码,因此没有线程或I/O).运行代码分析工具是可以的,这将允许我自动生成保存此状态的额外代码.我想我可能需要分析CIL才能做到这一点.
我想使用spring insight来跟踪我的spring mvcwebapp.启动tc服务器2.5开发人员版时,我的应用程序出现了,但我在控制台中看到以下消息:
20.10.2011 09:24:24 com.springsource.insight.intercept.trace.SimpleFrameBuilder enter
FATAL: Frame stack exceeded MAX_FRAMES_PER_TRACE limit or has been aborted limit: 3000 frameCount: 3000 aborted: false
20.10.2011 09:24:24 com.springsource.insight.collection.errorhandling.AdviceErrorHandlingAspect ajc$around$com_springsource_insight_collection_errorhandling_AdviceErrorHandlingAspect$1$e76a6b03
FATAL: Error swallowed in advice adviceexecution(void com.springsource.insight.collection.AbstractOperationCollectionAspect.afterReturning(Object, JoinPoint.StaticPart))
Run Code Online (Sandbox Code Playgroud)
-
java.lang.IllegalStateException: Imbalanced frame stack! (exit() called too many times)
com.springsource.insight.intercept.trace.ThreadLocalFrameBuilder.exit(ThreadLocalFrameBuilder.java:61)
com.springsource.insight.collection.DefaultOperationCollector.exit(DefaultOperationCollector.java:111)
com.springsource.insight.collection.DefaultOperationCollector.exitNormal(DefaultOperationCollector.java:67)
com.springsource.insight.plugin.springtx.TransactionOperationCollectionAspect.ajc$afterReturning$com_springsource_insight_plugin_springtx_TransactionOperationCollectionAspect$2$e13fb3a0(TransactionOperationCollectionAspect.aj:61)
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspect$3$2a73e96c(AbstractTransactionAspect.aj:78)
...
Run Code Online (Sandbox Code Playgroud)
我可以在此消息之后调用一些控制器操作,但在某些时候服务器只是拒绝处理我的请求并将相同的堆栈跟踪发送到浏览器.
有没有人有这个问题的经验?即使停用洞察力插件annotation,hibernate,jdbc或spring-tx不SOVE问题.
string thing = "etc";
thing = thing.GetName();
//now thing == "thing"
Run Code Online (Sandbox Code Playgroud)
这甚至可能吗?
public static string GetName(this object obj)
{
return ... POOF! //should == "thing"
}
Run Code Online (Sandbox Code Playgroud) 我遇到了Win64调试问题,看起来我们"缺少"调试信息.所以我做了一些研究,并为我们的旗舰产品重新创建了所有的.dproj文件.这有助于我将"失踪"的蓝球带回来.
但是现在我遇到了一个新问题:堆栈显示窗口中显示的(顶部)堆栈框架看起来是错误的,这导致局部变量不显示在局部变量窗格中,并且当鼠标悬停在某个变量上方时也不会.但是当我选择我认为正确的堆栈帧时,局部变量窗口不再是空的.悬停鼠标仍然没有显示任何内容.
还要检查链接的屏幕截图,这应该更清楚地说明事情.
相关的编译器选项
版本信息:
我已经使用了许多调试设置组合,但问题仍然存在于我的系统上.
我的同事计算机在相同的代码中具有完全相同的问题,因此至少它可以自信地重现.当尝试使用带有运行时bpl的小项目重现此问题时,问题似乎不会发生,或者我无法重现它.因此,我没有任何来源可以释放.
当然,这是一个(是)问题: - 还有其他人经历过这个吗? - 找到了解决方案?- 请分享! - 没找到解决方案?- >请为此问题添加评论/投票
我想添加一些图片来澄清,但不幸的是我的声誉还不够高.所以我只能添加图片的链接,对不起.





我知道这个话题已经覆盖生厌这里,并在互联网上其他地方-但希望这个问题很简单,因为我试图让我的头周围装配...
因此,如果我理解正确,ebp(基指针)将指向堆栈的顶部,并且esp(堆栈指针)将指向底部 - 因为堆栈向下增长.因此,esp指向"当前位置".因此,在函数调用中,一旦将ebp保存在堆栈上,就会为函数插入一个新的堆栈帧.因此,对于下图,如果您从N-3开始,您将通过函数调用转到N-2.但是当你在N-2时 - 你的ebp == 25和esp == 24(至少最初,在任何数据被放入堆栈之前)?
这是正确的还是我在这里切线?
谢谢!
stack-frame ×10
c# ×3
debugging ×3
.net ×2
java ×2
reflection ×2
abi ×1
assembly ×1
backtrace ×1
c ×1
c++ ×1
callstack ×1
cil ×1
delphi ×1
gcc ×1
memory ×1
optimization ×1
scala ×1
spring ×1
spring-mvc ×1
stack-trace ×1
watch ×1
win64 ×1
x86 ×1