亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

接口在線上服務(wù)器出現(xiàn)異常的時(shí)候,我們第一時(shí)間就是去服務(wù)器看下log,檢查log是否有異常堆棧信息,如果有異常堆棧信息的話,再結(jié)合api的access log,是非常容易找出問題所在的,所以我們要學(xué)會看異常堆棧信息。異常堆棧信息如何看呢?下面我們一起來看一下。

下面是一個(gè)簡單的demo:

package person.ismallboy.console;

import JAVA.io.IOException;

public class TestEx {
    private void fun1() throws IOException {
        throw new IOException("level 1 exception");
    }

    private void fun2() throws IOException {
        try {
            fun1();
            System.out.println("2");
        } catch (IOException e) {
            throw new IOException("level 2 exception", e);
        }
    }

    private void fun3() {
        try {
            fun2();
            System.out.println("3");
        } catch (IOException e) {
            throw new RuntimeException("level 3 exception", e);
        }
    }

    public static void main(String[] args) {
        try {
            new TestEx().fun3();
            System.out.println("0");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

執(zhí)行上面demo的main函數(shù),輸出結(jié)果如下:

Connected to the target VM, address: '127.0.0.1:57353', transport: 'socket'
java.lang.RuntimeException: level 3 exception
  at person.ismallboy.console.TestEx.fun3(TestEx.java:24)
  at person.ismallboy.console.TestEx.main(TestEx.java:30)
Caused by: java.io.IOException: level 2 exception
  at person.ismallboy.console.TestEx.fun2(TestEx.java:15)
  at person.ismallboy.console.TestEx.fun3(TestEx.java:21)
  ... 1 more
Caused by: java.io.IOException: level 1 exception
  at person.ismallboy.console.TestEx.fun1(TestEx.java:7)
  at person.ismallboy.console.TestEx.fun2(TestEx.java:12)
  ... 2 more
Disconnected from the target VM, address: '127.0.0.1:57353', transport: 'socket'

既然是堆棧,那肯定是FILO(先進(jìn)后出)的,了解過線程堆棧(比如函數(shù)調(diào)用的時(shí)候參數(shù)和局部變量的入棧和出棧)的同學(xué)應(yīng)該比較清楚。所以我們看打出來的異常堆棧的順序,也應(yīng)該是從下往上看,就是從第12行開始往上看,一直看到第2行,發(fā)現(xiàn)第10行才是問題的根源,異常是一層一層地往外拋出,直至拋出到最外層(即沒有catch為止)。第2行的RuntimeException只是真正異常的一個(gè)外層表現(xiàn)而已,異常的根源還是要看堆棧最底部的信息。本demo異常拋出的流程大概如下:

你真的會看異常堆棧信息么

 

所以,Caused by(中文是“由...造成的”意思)也就比較好理解了,就是這個(gè)異常時(shí)由哪里觸發(fā)的意思。fun3的異常是由fun2的異常觸發(fā)的,而fun2的異常又是由fun1的異常觸發(fā)的。

解決了異常堆棧查看順序的問題,我們細(xì)看上面demo打印出來的異常堆棧信息,會發(fā)現(xiàn),打印出來的堆棧信息不完整,比如第8行的“ ... 1 more”和第12行的“... 2 more”,為什么jvm會省略部分堆棧信息呢?下面我們繼續(xù)探討一下。

1.為什么有些堆棧信息被隱藏了?... 2 more

我們來看一下打印異常堆棧信息的源碼,輸出函數(shù)是

java.lang.Throwable#printEnclosedStackTrace

輸出異常堆棧函數(shù)源代碼如下:

/**
     * Print our stack trace as an enclosed exception for the specified
     * stack trace.
     */
    private void printEnclosedStackTrace(PrintStreamOrWriter s,
                                         StackTraceElement[] enclosingTrace,
                                         String caption,
                                         String prefix,
                                         Set<Throwable> dejaVu) {
        assert Thread.holdsLock(s.lock());
        if (dejaVu.contains(this)) {
            s.println("t[CIRCULAR REFERENCE:" + this + "]");
        } else {
            dejaVu.add(this);
            // Compute number of frames in common between this and enclosing trace
            StackTraceElement[] trace = getOurStackTrace();
            int m = trace.length - 1;
            int n = enclosingTrace.length - 1;
            while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
                m--; n--;
            }
            int framesInCommon = trace.length - 1 - m;

            // Print our stack trace
            s.println(prefix + caption + this);
            for (int i = 0; i <= m; i++)
                s.println(prefix + "tat " + trace[i]);
            if (framesInCommon != 0)
                s.println(prefix + "t... " + framesInCommon + " more");

            // Print suppressed exceptions, if any
            for (Throwable se : getSuppressed())
                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
                                           prefix +"t", dejaVu);

            // Print cause, if any
            Throwable ourCause = getCause();
            if (ourCause != null)
                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
        }
    }

我們來分析一下這個(gè)函數(shù),這里其實(shí)是一個(gè)回調(diào)輸出堆棧的過程。我們先來說一下為什么會隱藏部分堆棧,當(dāng)然是為了提高性能,省略一些不必要的輸出啦,輸出的內(nèi)容越多,io耗時(shí)越慢嘛。

其實(shí)“... n more”的部分是重復(fù)的堆棧部分。我們分析一下上面這個(gè)函數(shù)“printEnclosedStackTrace”,翻譯為“打印封閉堆棧跟蹤信息”,“封閉”暫且可以理解為“完整的”,這個(gè)函數(shù)有兩個(gè)比較重要的變量,分別是“enclosingTrace”和“trace ”,這兩個(gè)參數(shù)是什么關(guān)系呢?其實(shí)可以簡單理解為“enclosingTrace”是“trace ”的父級堆棧,函數(shù)printEnclosedStackTrace中的while循環(huán),就是為倒序找出“enclosingTrace”和“trace ”中從哪一個(gè)棧幀開始就不一樣了,即“enclosingTrace”和“trace ”是有一部分是一樣的(從數(shù)組后面倒回來),就是為了算出有多少個(gè)棧幀信息是重復(fù)可以隱藏的,相同的棧幀就不用重復(fù)輸出啦。下圖就是第12行“... 2 more”隱藏的棧幀信息:

你真的會看異常堆棧信息么

調(diào)試信息

按照上面的堆棧輸出,第12行“... 2 more”隱藏2行堆棧信息,其實(shí)就是第7和第8行的棧幀信息;然后第8行“ ... 1 more”隱藏的1個(gè)堆棧信息,其實(shí)就是第4行的那個(gè)棧幀。這樣應(yīng)該好理解了吧,每個(gè)異常都輸出一個(gè)完整的堆棧信息的話,都是從main函數(shù)開始,到當(dāng)前的函數(shù)的所有函數(shù)調(diào)用的棧幀信息,里面函數(shù)的調(diào)用棧幀信息都會包括外層的函數(shù)調(diào)用棧幀信息,所以都輸出的話,很多都是重復(fù)的,為了提高效率,減少io以及輸出的內(nèi)容太多又雜亂,所以jvm以“... n more”的方式隱藏了重復(fù)的部分。

當(dāng)然,如果想不隱藏,可以重寫java.lang.Throwable#printEnclosedStackTrace,去掉while部分,就可以看到每個(gè)異常的完整堆棧信息了,可以參考https://blog.csdn.net/michaelehome/article/details/79484722來驗(yàn)證。

 

參考:

https://www.jianshu.com/p/9f902c5517f8

https://blog.csdn.net/michaelehome/article/details/79484722

分享到:
標(biāo)簽:堆棧
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定