簡體   English   中英

Java - 保存/恢復調用堆棧

[英]Java - Save/restore call stack

是否可以在執行期間保存調用堆棧的狀態,然后將堆棧恢復到該狀態,在最頂層的方法調用中重新啟動?

我強烈建議改變你的范例。 而不是操縱調用堆棧(並且很可能破壞您的JVM),考慮在算法中以某種方式合並“調用堆棧”。

您可以使用策略/命令/撤消設計模式並將對象存儲到您自己的邏輯堆棧中 ,您可以完全控制它們。

有一個相關的問題從遞歸到迭代的方法有很多好的答案。

您可以使用正常的程序流控制從特定的調用堆棧重新啟動,而不是直接與調用堆棧混亂。 一種方法是例外:

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

保存當前的調用堆棧非常簡單。 Thread類有一些面向堆棧跟蹤的函數。 最有可能這就是你要找的 -

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

現在您已經保存了堆棧跟蹤,以便稍后使用。 我不知道你的意思是通過恢復堆棧跟蹤。

絕對可以觀察堆棧跟蹤。 在完成太多的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()。 如果你的主線程/代碼比這個線程運行得更快,它有可能會錯過方法,但它很可能會捕獲所有內容。

您可以在其中包含一個時間戳(新的Date()),以查看您的方法調用返回的時間。

為了得到你想要的東西,你可以在堆棧跟蹤中保存這些方法調用,並使用反射稍后再次調用方法。 但是,我認為這將是一個不好的做法。

我認為你正在尋找基於Continuations的東西...... Java Flow是一個古老的項目,但我認為它完全符合你的要求 - 將堆棧幀保存為Continuation對象,使用字節碼“magic” - 即一些額外的代碼被編織到您的代碼中以允許將堆棧幀保存到對象中。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM