是否可以在执行期间保存调用堆栈的状态,然后将堆栈恢复到该状态,在最顶层的方法调用中重新启动?
答案 0 :(得分:10)
我强烈建议改变你的范例。而不是操纵调用堆栈(并且很可能破坏你的JVM),考虑在算法中以某种方式合并“调用堆栈”。
您可以使用策略/命令/撤消设计模式并将对象存储到您自己的逻辑堆栈,您可以完全控制它们。
有一个相关问题Way to go from recursion to iteration有很多好的答案。
答案 1 :(得分:3)
您可以使用正常的程序流控制从特定的调用堆栈重新启动,而不是直接与调用堆栈混乱。一种方法是例外:
Result findResult() {
while (true) {
Data data = getData();
try {
return processData(data);
} catch (OutOfDateException e) {
/* fall through */
}
}
}
Result processData(Data data) throws OutOfDateException {
/* ... */
processData2(otherData)
/* ... */
}
IntermediateResult processData2(OtherData otherData) throws OutOfDateException {
/* ... */
if (myDataWasTooOld())
throw new OutOfDateException();
/* ... */
}
在该示例中,如果processData2()
抛出异常,则使用processData2()
的新值重新创建相同的调用堆栈(processData()
调用data
)。
答案 2 :(得分:0)
保存当前调用堆栈非常简单。 Thread
类具有一些面向堆栈跟踪的函数。很可能这就是你要找的 -
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
现在您已经保存了堆栈跟踪,以便稍后使用。我不确定你的意思是恢复堆栈跟踪。
答案 3 :(得分:0)
绝对可以观察堆栈跟踪。在完成太多的shell脚本并为每行代码获取响应之前,我已经完成了这项工作。我所做的是创建一个监听器线程,它是主线程的子级。
这样的事情:
public class Debugger implements Serializable {
private static final long serialVersionUID = 1L;
private Thread parent;
private String packageName;
private File outputFile;
private boolean alive;
public Debugger(Thread parent, String packageName, File outputFile) {
this.parent = parent;
this.packageName = packageName;
this.outputFile = outputFile;
alive = true;
}
public void run() throws FileNotFoundException {
PrintStream ps = new PrintStream(outputFile);
alive = true;
String lastClassName = "";
while (parent.isAlive() && alive) {
for (StackTraceElement ste : parent.getStackTrace()) {
if (ste.getClassName().startsWith(packageName)) {
if (!ste.getClassName().equals(lastClassName)) {
ps.println(ste.toString());
lastClassName = ste.getClassName();
}
break;
}
}
}
ps.close();
}
public void kill() {
alive = false;
}
}
如果在要调试的代码的开头创建此对象,它将在您调用的包前缀/子字符串中的每个新方法中写入您的文件。然后只需要在要监视堆栈跟踪的代码上调用kill()。如果你的主线程/代码运行得比这个线程快,它有可能会错过方法,但它很可能会捕获所有内容。
您可以在其中添加时间戳(新的日期()),以查看您的方法调用返回的时间。
为了得到你想要的东西,你可以在堆栈跟踪中保存这些方法调用,并使用反射稍后再次调用这些方法。但是,我确实认为这是一种不好的做法。
答案 4 :(得分:0)
我认为你正在寻找基于Continuations的东西... Java Flow是一个古老的项目,但我认为它完全符合你的要求 - 使用字节码“魔术”将堆栈帧保存为Continuation对象 - 也就是说,一些额外的代码被编织到您的代码中,以允许将堆栈帧保存到对象中。
http://commons.apache.org/sandbox/commons-javaflow/tutorial.html