天天看點

實戰|内部類導緻反序列化抛出StackOverflowError異常

問題

用戶端送出請求,通過網關通路項目A的接口擷取資源資料,通路逾時,報504

解決過程

  • 第一步:在項目A中先對接口進行單測,并列印耗時時間,顯示500毫秒,故确認非接口性能問題
  • 第二步:網關調用遠端調試項目A,在用戶端發起請求至項目A該接口傳回最終資料,時間隻在一瞬間,故确認問題出在網關接收傳回資料的環節
  • 第三步:遠端調試網關,将斷點定位在網關擷取到項目A傳回資料的那行代碼,一步一步走下去,發現反序列傳回資料的方法抛出StackOverflowError異常
    • StackOverflowError是棧溢出異常,發生原因是方法調用太多,棧空間不夠用,常見于遞歸調用
  • 第四步:檢查傳回資料,發現傳回資料内部一個屬性值指向外部類的引用,發生了死循環引用,示例結構如下
data = {[email protected]}{
  name = "名稱外部"
  child = {[email protected]}{
     name = "名稱内部"
     this$0 = {[email protected]}{
       name = "名稱外部"
       child = {[email protected]}{
          ...省略...循環
       }
     }
  }
}
           
  • 第五步:定位到問題出在傳回資料出現了内部遞歸指向,即網關在反序列化傳回資料時,先建立了A,然後建立A的屬性name、child,但是屬性child的屬性又指向A,于是又初始化A屬性,造成了死循環調用,最終抛出StackOverflowError異常
  • 第六步:回到項目A檢查傳回資料的資料結構,發現發生遞歸引用的那個屬性的類型是一個内部類,經查閱,了解到内部類在建立時會預設擁有一個外部類執行個體的引用,故将内部類改成靜态内部類,問題解決

解決思路

  1. 先排查項目接口本身是否有問題
  2. 然後網關調用接口,判斷接口傳回速度是否有問題
  3. 最後定位到網關傳回環節有問題
  4. 根據該環節所報異常排查最終問題

繼續閱讀