摘要:于是懷疑是不是對(duì)一個(gè)類的做了緩存,在第一次加載這個(gè)類出現(xiàn)以后,后續(xù)再嘗試加載就直接拋出。上述類的的作用是是一個(gè)空的類,里面有一個(gè)的靜態(tài)成員。
問題
今天在排查一個(gè)線上的問題,線上的一個(gè)應(yīng)用在初始化一個(gè)類的靜態(tài)字段的時(shí)候出現(xiàn)了 NoClassDefFoundError,并且在導(dǎo)致 NoClassDefFoundError 出現(xiàn)的根本原因消失后,后續(xù)再次嘗試初始化這個(gè)類的時(shí)候,持續(xù)出現(xiàn)了 NoClassDefFoundError。
于是懷疑 JVM 是不是對(duì)一個(gè)類的 NoClassDefFoundError 做了緩存,在第一次加載這個(gè)類出現(xiàn) NoClassDefFoundError 以后,后續(xù)再嘗試加載就直接拋出 NoClassDefFoundError。
實(shí)驗(yàn)為了證實(shí)自己的猜想,嘗試設(shè)計(jì)了一個(gè)簡單的實(shí)驗(yàn),一個(gè)涉及三個(gè)類
public class Test1 { static Test2 test2 = new Test2(); }
public class Test2 { }
public class Test { public static void main(String... args) throws Exception { while(true) { System.out.println("================================"); try { new Test1(); // 嘗試實(shí)例化 Test1,觸發(fā) NoClassDefFoundError } catch (Throwable e) { e.printStackTrace(); try { Test.class.getClassLoader().loadClass("Test2"); // 嘗試加載 Test2,用于證實(shí)當(dāng)將 // Test2.class 拷貝到 ClassPath 下的時(shí)候, // Test2 就可以加載到了。 } catch (Throwable ex) { ex.printStackTrace(); } } Thread.sleep(3000); } } }
上述類的的作用是:Test2 是一個(gè)空的類,Test1 里面有一個(gè) Test2 的靜態(tài)成員。Test 是程序的主入口,在一個(gè)無限循環(huán)內(nèi)部,不斷地嘗試去實(shí)例化 Test1,并且在加載 Test1 出現(xiàn)異常的時(shí)候,嘗試加載一下 Test2。
實(shí)驗(yàn)的步驟是:
編譯以上類,運(yùn)行 javac Test.java
將生成出的 Test2.class 重命名成 Test2.class.bak
運(yùn)行 java Test,這個(gè)時(shí)候程序去加載 Test1 的時(shí)候,就會(huì)出現(xiàn) NoClassDefFoundError,并且在嘗試加載 Test2 的時(shí)候,會(huì)出現(xiàn) ClassNotFoundException。
將第二步重命名的 Test2.class.bak 該回成 Test2.class,這個(gè)時(shí)候程序去加載 Test1 的時(shí)候,就會(huì)出現(xiàn) NoClassDefFoundError,在加載 Test2 的時(shí)候,不會(huì)出現(xiàn) ClassNotFoundException。
實(shí)驗(yàn)的第二步的目的是為了程序在加載 Test1 的時(shí)候因?yàn)檎也坏?Test2 出現(xiàn) NoClassDefFoundError,第四步是為了和第二步做對(duì)照,說明在后續(xù)程序可以加載到 Test2 的時(shí)候,在實(shí)例化 Test1 的時(shí)候,依舊出現(xiàn) NoClassDefFoundError
在我的機(jī)器上,按照上面的方式去操作,結(jié)果如下:
結(jié)果正如預(yù)期,即使在后面 Test2 在 ClassPath 下的時(shí)候,NoClassDefFoundError 依舊出現(xiàn),所以 JVM 里面肯定有地方對(duì) NoClassDefFoundError 做了緩存。
JVM 里面的實(shí)現(xiàn)帶著這個(gè)疑問,請(qǐng)教了部門里面的 JVM 專家,這個(gè)猜測得到了證實(shí),并且他給出了 JVM 內(nèi)部具體處理這段邏輯的代碼,處理的代碼在 JDK 的 instanceKlass.cpp 這個(gè)文件里面:
bool instanceKlass::link_class_impl( instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) { // check for error state if (this_oop->is_in_error_state()) { ResourceMark rm(THREAD); THROW_MSG_(vmSymbols::java_lang_NoClassDefFoundError(), this_oop->external_name(), false); } // return if already verified if (this_oop->is_linked()) { return true; }
并且在 instanceClass.hpp 這個(gè)文件中,定義了類的 _init_state,其中,is_in_error_state 這個(gè)方法的定義如下:
bool is_in_error_state() const { return _init_state == initialization_error; }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/64242.html
摘要:看到的只是,而由泛型附加的類型信息對(duì)來說是不可見的。然后再加載執(zhí)行類的靜態(tài)變量以及靜態(tài)語句塊。接口中基本數(shù)據(jù)類型為而抽類象不是的。本地方法接口主要是調(diào)用或?qū)崿F(xiàn)的本地方法及返回結(jié)果。用戶自定義類加載器,在程序運(yùn)行期間,通過的子類動(dòng)態(tài)加載。 編譯機(jī)制 編譯主要是把?.Java文件轉(zhuǎn)換為 .class 文件。其中轉(zhuǎn)換后的 .class 文件就包含了元數(shù)據(jù),方法信息等一些信息。比如說元數(shù)據(jù)就...
摘要:出現(xiàn)錯(cuò)誤引發(fā)崩潰日志的流程分析這個(gè)錯(cuò)誤是應(yīng)用的方法總數(shù)限制造成的。 目錄介紹 1.1 java.lang.ClassNotFoundException類找不到異常 1.2 java.util.concurrent.TimeoutException連接超時(shí)崩潰 1.3 java.lang.NumberFormatException格式轉(zhuǎn)化錯(cuò)誤 1.4 java.lang.Illegal...
摘要:可實(shí)現(xiàn)單例模式代碼塊初始化靜態(tài)變量,只被執(zhí)行一次內(nèi)部類不能與外部類重名,只能訪問外部類靜態(tài)數(shù)據(jù)包括私有多分支選擇整型或字符類型變量或整數(shù)表達(dá)式開始支持。 前言 大學(xué)期間接觸 Java 的時(shí)間也不短了,不論學(xué)習(xí)還是實(shí)習(xí),都讓我發(fā)覺基礎(chǔ)的重要性?;ヂ?lián)網(wǎng)發(fā)展太快了,各種框架各種技術(shù)更新迭代的速度非常快,可能你剛好掌握了一門技術(shù)的應(yīng)用,它卻已經(jīng)走在淘汰的邊緣了。 而學(xué)習(xí)新技術(shù)總要付出一定的時(shí)間...
摘要:方案一設(shè)置運(yùn)行環(huán)境變量運(yùn)行后會(huì)把文件生成在目錄下動(dòng)態(tài)代理時(shí)生成文件缺點(diǎn)是只適用于動(dòng)態(tài)代理方案二使用可以出中所有已加載的。 由于動(dòng)態(tài)代理生成的class是直接以二進(jìn)制的方式加載進(jìn)內(nèi)存中的,并沒有對(duì)應(yīng)的.class文件生成,所以如果想通過反編譯工具查看動(dòng)態(tài)代理生成的代碼需要通過特殊的手段來處理。 方案一 設(shè)置運(yùn)行環(huán)境變量,運(yùn)行后會(huì)把class文件生成在classpath目錄下 //動(dòng)態(tài)代理...
摘要:但是將導(dǎo)入工程后,在使用時(shí)會(huì)出現(xiàn)等錯(cuò)誤消息。初步認(rèn)為是與自帶的沖突。再運(yùn)行工程,這個(gè)錯(cuò)誤不再出現(xiàn)了,奇跡般的沒問題了。我的理解是這樣,不知道對(duì)不對(duì),歡迎大俠指正。工程中下默認(rèn)的是,而則應(yīng)該是。所以按照該文的解決方法,更改就好了。 JSON解析庫有很多,諸如Jackson,Json-lib,org.json,Gson和fastjson等,但是fastjson以其解析速度最快而脫穎而出。詳...
閱讀 1844·2021-11-11 16:55
閱讀 767·2019-08-30 15:53
閱讀 3604·2019-08-30 15:45
閱讀 753·2019-08-30 14:10
閱讀 3280·2019-08-30 12:46
閱讀 2137·2019-08-29 13:15
閱讀 2037·2019-08-26 13:48
閱讀 948·2019-08-26 12:23