Java中的NoClassDefFoundError報(bào)錯(cuò)含義解析
引言
半夜睡得正香的時(shí)候,突然接到警告電話,于是翻起身就打卡電腦連上環(huán)境查看是什么情況?登錄上之后發(fā)現(xiàn)有個(gè)微服務(wù)占用的句柄數(shù)量一直在持續(xù)上漲,最終導(dǎo)致了微服務(wù)內(nèi)存溢出掛掉了。這個(gè)微服務(wù)在運(yùn)行的過程中會(huì)建立SSH
連接,且之前這個(gè)微服務(wù)已經(jīng)遇到過很多次類似的情況了,因此第一反應(yīng)是哪里建立的連接又沒有關(guān)閉。
猜肯定是猜不出來的,所以第一步肯定先看下日志里面哪里在報(bào)錯(cuò),然后才好對癥下藥。打開日志之后,經(jīng)過一番排查,發(fā)現(xiàn)日志里面有個(gè)很奇怪的報(bào)錯(cuò),日志里面有打印NoClassDefFoundError
。最開始的我對這個(gè)錯(cuò)誤的理解是不夠深刻的,我的第一反應(yīng)是Class
文件找不到了。于是我切換到微服務(wù)的路徑下,去找這個(gè)Class
文件,發(fā)現(xiàn)文件是存在的。于是我又想,難道是文件的權(quán)限不對?我又用了ll
命令看了一下文件的權(quán)限,發(fā)現(xiàn)文件的權(quán)限也是對的。這個(gè)時(shí)候我有點(diǎn)懵了,心想完了,這道題不會(huì)呀,老師沒教過呀!
沒辦法,為了保住工作,硬著頭皮還是得上。俗話說,源碼之下無秘密,只有根據(jù)堆棧找到對應(yīng)的源代碼進(jìn)行分析,看看有什么懷疑點(diǎn),然后又從網(wǎng)上搜索了一下NoClassDefFoundError
報(bào)錯(cuò)的含義。經(jīng)過我的深思熟慮終于發(fā)現(xiàn)了問題的所在。
NoClassDefFoundError的報(bào)錯(cuò)含義
首先需要了解一下NoClassDefFoundError
的報(bào)錯(cuò)含義,參考why-am-i-getting-a-noclassdeffounderror-in-java這個(gè)帖子:
這段話說:NoClassDefFoundError這個(gè)報(bào)錯(cuò)說明之前JVM嘗試過去加載這個(gè)類,但是因?yàn)槟承┰蚴×恕,F(xiàn)在又要使用到這個(gè)類,所以又會(huì)觸發(fā)這個(gè)類的加載,但是因?yàn)橹凹虞d這個(gè)類失敗了,所以這次就不會(huì)去加載這個(gè)類了,而是直接拋出NoClassDefFoundError這個(gè)報(bào)錯(cuò)。
解析
如果上面這段話不好理解,可以看下面這個(gè)例子,這個(gè)例子也是來自于上面那個(gè)帖子中的回答:
public class NoClassDefFoundError { public static void main(String[] args) { try { // 這里嘗試new一個(gè)對象,會(huì)觸發(fā)SimpleCalculator的第一次加載 SimpleCalculator calculator1 = new SimpleCalculator(); } catch (Throwable t) { System.out.println(t); } // 這里又嘗試new一個(gè)對象,會(huì)觸發(fā)SimpleCalculator的第二次加載 SimpleCalculator calculator2 = new SimpleCalculator(); } ? } ? class SimpleCalculator { // 類加載的時(shí)候會(huì)初始化這個(gè)類變量,這里會(huì)拋出一個(gè)運(yùn)行時(shí)異常 static int undefined = 1 / 0; }
從上面的運(yùn)行結(jié)果可以看到,在代碼的第12行拋出了NoClassDefFoundError
的報(bào)錯(cuò),這里也是第二次嘗試加載這個(gè)類的地方。第一次嘗試初始化SimpleCalculator
這個(gè)類時(shí),因?yàn)槌跏蓟瘯?huì)初始化 undefined
這個(gè)變量,而這個(gè)變量在初始化過程中會(huì)拋出一個(gè)異常,滿足了第一次報(bào)錯(cuò)的條件,然后第12行嘗試第二次初始化這個(gè)類,因?yàn)榈谝淮我呀?jīng)初始化失敗了,這個(gè)時(shí)候 JVM 就直接拋出NoClassDefFoundError
這個(gè)報(bào)錯(cuò),而不是嘗試再次去加載這個(gè)類。
當(dāng)然實(shí)際的代碼不可能會(huì)寫出這么明顯的Bug,我出問題的代碼大概是長如下這樣:
public class XXXUtils { private static final XXXBean bean = SpringContextUtils.getBean(XXXBean.class); } ? public class SpringContextUtils { public static <T> T getBean(Class<T> clazz) { return context.getBean(clazz); } } ? public class XXXClazz { public static void xxxMethod() { XXXUtils.xxxMethod(); } } ? public class Session { try { XXX conn = xxx; } finnaly { XXXUtils.closeConn(conn); } }
其中的工具類 XXXUtils
實(shí)際依賴了 SpringContexUtils
來獲取 Bean
,也就是依賴 Spring
上下文初始化好。但是實(shí)際在服務(wù)啟動(dòng)的過程中又觸發(fā)了 XXXClass
的 xxxMethod
調(diào)用了 XXXUtils
的方法,這個(gè)時(shí)候就會(huì)觸發(fā) XXXUtils
的類加載,也就會(huì)觸發(fā)它的 bean
變量的初始化,但是由于這個(gè)時(shí)候 Spring
上下文還沒有初始化好,因此調(diào)用 SpringContextUtils.getBean()
方法就會(huì)拋出異常。在第一次初始化 XXXUtils
失敗之后,等到服務(wù)正常啟動(dòng),其它地方再調(diào)用 XXXUtils
的方法時(shí),就會(huì)拋出 NoClassDefFoundError
錯(cuò)誤,導(dǎo)致了 XXXUtils
的所有方法都不可用,而正常的SSH連接結(jié)束之后,會(huì)調(diào)用 XXXUtils.closeConn()
方法關(guān)閉連接,當(dāng)然,因?yàn)檫@個(gè)時(shí)候方法不可用,所以連接也關(guān)不掉,最終導(dǎo)致了的句柄數(shù)量不斷上漲,服務(wù)也掛掉了。
以上就是Java中的NoClassDefFoundError報(bào)錯(cuò)解析的詳細(xì)內(nèi)容,更多關(guān)于Java中的NoClassDefFoundError報(bào)錯(cuò)解析的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring的連接數(shù)據(jù)庫以及JDBC模板(實(shí)例講解)
下面小編就為大家?guī)硪黄猄pring的連接數(shù)據(jù)庫以及JDBC模板(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10springboot應(yīng)用服務(wù)啟動(dòng)事件的監(jiān)聽實(shí)現(xiàn)
本文主要介紹了springboot應(yīng)用服務(wù)啟動(dòng)事件的監(jiān)聽實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04Spring的Bean生命周期之BeanDefinition詳解
這篇文章主要介紹了Spring的Bean生命周期之BeanDefinition詳解,在spring bean創(chuàng)建過程 依賴 BeanDefinition 中的信息處理bean的生產(chǎn),BeanDefinition 是 Spring Framework 中定義 Bean 的配置元信息接口,需要的朋友可以參考下2023-12-12使用jsoup解析html的table中的文本信息實(shí)例
今天小編就為大家分享一篇使用jsoup解析html的table中的文本信息實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05通過Java 程序獲取Word中指定圖片的坐標(biāo)位置
本文介紹通過Java程序獲取Word文檔中指定圖片的坐標(biāo)位置,程序運(yùn)行環(huán)境是jdk1.8開發(fā)環(huán)境idea,通過java程序代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-05-05mybatis多個(gè)區(qū)間處理方式(雙foreach循環(huán))
這篇文章主要介紹了mybatis多個(gè)區(qū)間處理方式(雙foreach循環(huán)),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02詳解IDEA用maven創(chuàng)建springMVC項(xiàng)目和配置
本篇文章主要介紹了詳解IDEA用maven創(chuàng)建springMVC項(xiàng)目和配置 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09