简体   繁体   中英

Java - Save/restore call stack

是否可以在执行期间保存调用堆栈的状态,然后将堆栈恢复到该状态,在最顶层的方法调用中重新启动?

I strongly suggest to change your paradigm. Instead of manipulating the call stack (and very probably corrupting your JVM), think about incorporating the "call stack" somehow in your algorithm.

You may use the Strategy/Command/Undo design pattern and store the objects to your own logical stack , over which you have full control.

There is a related question Way to go from recursion to iteration with a lot of good answers.

You can restart from a specific call stack with normal program flow control, instead of messing directly with call stacks. One way is with exceptions:

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();
    /* ... */
}

In the example, if processData2() throws the exception, the same call stack ( processData2() called from processData() ) is recreated with a new value for data .

Saving the current call stack is quite simple. The Thread class has some stack trace oriented functions. Most likely this is what you are looking for -

StackTraceElement[] stack = Thread.currentThread().getStackTrace();

And now you have saved your stack trace, to be used later however you will. Im not sure what you mean by restore the stack trace though.

It is definitely possible to watch the stack trace. I have done this before after doing too much shell scripting and getting a response for every line of code. What I did was to create a listener thread that is a child of the main thread.

Something like this:

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;
    }
}

If you create this object at the beginning of the code you would like to debug, it will write to your file every new method in your package prefix/substring that is called. Then just call kill() at the code you want to watch for the stack trace. There is a chance that it will miss methods if your main thread/code runs faster than this thread, but it will more than likely catch everything.

You could include a timestamp (new Date()) there to see how long your method calls take to return as well.

In order to get what you wanted, you could save these method calls within the stack trace and use reflection to invoke the methods again later. However, I do think that would be a bad practice.

I think you're looking for something Continuations based... Java Flow is an old project, but I think it does exactly what you ask - saves stack frames as a Continuation object, using bytecode "magic" - that is, some extra code is weaved into your code to allow for stack frames to be saved into an object.

http://commons.apache.org/sandbox/commons-javaflow/tutorial.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM