日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ClassNotFoundException:是否减慢了您的JVM?

發(fā)布時間:2023/12/3 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ClassNotFoundException:是否减慢了您的JVM? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

大多數(shù)Java開發(fā)人員都熟悉臭名昭著且非常常見的java.lang.ClassNotFoundException 。 雖然通常已經(jīng)很好地了解了此問題的根源(類路徑中缺少類/庫,類加載器委派問題等),但對整體JVM和性能的影響通常是未知的。 這種情況可能會對您的應(yīng)用程序響應(yīng)時間和可伸縮性產(chǎn)生重大影響。

部署了多個應(yīng)用程序的大型Java EE企業(yè)系統(tǒng)最容易遭受此類問題的影響,因為在運(yùn)行時會激活大量不同的應(yīng)用程序類加載器。 除非確定了明確的業(yè)務(wù)影響并實施了緊密的日志監(jiān)視,否則這將面臨面臨“未檢測到” ClassNotFoundException的風(fēng)險,結(jié)果是:持續(xù)的性能影響以及可能的JVM類加載IO和線程鎖爭用。

下面的文章和示例程序?qū)⒄f明從客戶生產(chǎn)系統(tǒng)中發(fā)現(xiàn)的ClassNotFoundException的任何出現(xiàn)都應(yīng)予以認(rèn)真對待并Swift解決。

Java類加載:缺少鏈接以獲得最佳性能

對這個性能問題的正確理解始于對Java類加載模型的正確了解。 ClassNotFoundException本質(zhì)上意味著JVM無法定位和/或加載特定的Java類,例如:

  • Class.forName()方法
  • ClassLoader.findSystemClass()方法
  • ClassLoader.loadClass()方法

雖然應(yīng)用程序的類加載僅在JVM生命周期中(或通過動態(tài)重新部署功能)發(fā)生一次,但某些應(yīng)用程序也依賴于動態(tài)類加載操作。

無論如何,重復(fù)的有效和“失敗”類加載操作可能非常麻煩,特別是當(dāng)默認(rèn)JDK java.lang.ClassLoader本身嘗試加載過程時。 實際上,由于向后兼容性,默認(rèn)的JDK 1.7+行為將僅允許一次加載一個類,除非將類加載器標(biāo)記為“具有并行功能”。 請記住,即使同步僅在類級別完成,針對相同類名的重復(fù)類加載失敗仍將觸發(fā)線程鎖爭用,具體取決于您正在處理的Java線程并發(fā)級別。 回到JDK 1.6時,情況最糟糕,在類加載器實例級別系統(tǒng)地完成了同步。

因此,諸如JBoss WildFly 8之類的Java EE容器正在使用它們自己的內(nèi)部并發(fā)類加載器來加載應(yīng)用程序類。 這些類加載器實現(xiàn)了更細(xì)粒度的鎖定,因此允許同時從類加載器的同一實例加載不同的類。 這也與最新的JDK 1.7+改進(jìn)保持一致,后者引入了對多線程自定義類加載器的支持,這也有助于防止某些類加載器出現(xiàn)死鎖情況。

話雖這么說,系統(tǒng)級類(例如java。*和Java EE容器模塊)的類加載仍然依靠默認(rèn)的JDK ClassLoader。 這意味著相同類名(例如ClassNotFoundException)的重復(fù)類加載失敗仍然會觸發(fā)嚴(yán)重的線程鎖爭用。 這正是我們將在本文的其余部分中重復(fù)和演示的內(nèi)容。

線程鎖爭用–問題復(fù)制

為了重新創(chuàng)建和模擬此問題,我們根據(jù)以下規(guī)范創(chuàng)建了一個簡單的應(yīng)用程序:

  • 一個JAX-RS(REST)Web服務(wù),對系統(tǒng)包級別“位于”的虛擬類名稱執(zhí)行Class.forName():

字符串className =“ java.lang.WrongClassName”;

類。 forName (className);

  • JRE:HotSpot JDK 1.7 @ 64位
  • Java EE容器: JBoss WildFly 8
  • 負(fù)載測試工具: Apache JMeter
  • Java監(jiān)控:JVisualVM
  • Java并發(fā)故障排除: JVM線程轉(zhuǎn)儲分析

該仿真實際上與20個線程同時執(zhí)行JAX-RS Web服務(wù)。 每次調(diào)用都會生成ClassNotFoundException。 為了減少對IO的影響并僅關(guān)注類加載爭用,完全禁用了日志記錄。

現(xiàn)在,讓我們看看從30到60秒的運(yùn)行情況來看JVisualVM的結(jié)果。 我們可以清楚地看到很多BLOCKED線程正在等待獲取對象監(jiān)視器上的鎖。

對JVM線程轉(zhuǎn)儲的分析清楚地揭示了問題所在:線程鎖爭用。 從執(zhí)行堆棧跟蹤中我們可以看到JBoss將類的加載委托給JDK ClassLoader ...為什么? 這是因為檢測到我們錯誤的Java類名稱是系統(tǒng)類路徑的一部分,例如java。*。 在這種情況下,JBoss將把加載委托給系統(tǒng)類加載器,從而觸發(fā)該特定類名稱的系統(tǒng)同步,并等待來自其他線程的服務(wù)員等待獲取鎖以加載相同的類名稱。

許多線程正在等待獲取LOCK 0x00000000ab84c0c8…

"default task-15" prio=6 tid=0x0000000014849800 nid=0x2050 waiting for monitor entry [0x000000001009d000] java.lang.Thread.State: BLOCKED (on object monitor) at java.lang.ClassLoader.loadClass(ClassLoader.java:403) - waiting to lock <0x00000000ab84c0c8> (a java.lang.Object)// Waiting to acquire a LOCK held by Thread “default task-20” at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) // JBoss now delegates to system ClassLoader.. at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:371) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:119) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:186) at org.jboss.tools.examples.rest.MemberResourceRESTService.SystemCLFailure(MemberResourceRESTService.java:176) at org.jboss.tools.examples.rest.MemberResourceRESTService$Proxy$_$$_WeldClientProxy.SystemCLFailure(Unknown Source) at sun.reflect.GeneratedMethodAccessor15.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) ……………………..

罪犯線程–默認(rèn)任務(wù)20

"default task-20" prio=6 tid=0x000000000e3a3000 nid=0x21d8 runnable [0x0000000010e7d000] java.lang.Thread.State: RUNNABLE at java.lang.Throwable.fillInStackTrace(Native Method) at java.lang.Throwable.fillInStackTrace(Throwable.java:782) - locked <0x00000000a09585c8> (a java.lang.ClassNotFoundException) at java.lang.Throwable.<init>(Throwable.java:287) at java.lang.Exception.<init>(Exception.java:84) at java.lang.ReflectiveOperationException.<init>(ReflectiveOperationException.java:75) at java.lang.ClassNotFoundException.<init>(ClassNotFoundException.java:82) // ClassNotFoundException! at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:423) - locked <0x00000000ab84c0e0> (a java.lang.Object) at java.lang.ClassLoader.loadClass(ClassLoader.java:410) - locked <0x00000000ab84c0c8> (a java.lang.Object) // java.lang.ClassLoader: LOCK acquired at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:371) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:119) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:186) at org.jboss.tools.examples.rest.MemberResourceRESTService.SystemCLFailure(MemberResourceRESTService.java:176) at org.jboss.tools.examples.rest.MemberResourceRESTService$Proxy$_$$_WeldClientProxy.SystemCLFailure(Unknown Source) …………………………………

現(xiàn)在,讓我們用標(biāo)記為“應(yīng)用程序”包的一部分的Java類替換我們的類名稱,然后在相同的負(fù)載條件下重新運(yùn)行測試。

String className = "org.ph.WrongClassName"; Class.forName(className);

如我們所見,我們不再處理阻塞的線程……為什么呢? 讓我們看一下JVM線程轉(zhuǎn)儲,以更好地理解這種行為變化。

"default task-51" prio=6 tid=0x000000000dd33000 nid=0x200c runnable [0x000000001d76d000] java.lang.Thread.State: RUNNABLE at java.io.WinNTFileSystem.getBooleanAttributes(Native Method) // IO overhead due to JAR file search operation at java.io.File.exists(File.java:772) at org.jboss.vfs.spi.RootFileSystem.exists(RootFileSystem.java:99) at org.jboss.vfs.VirtualFile.exists(VirtualFile.java:192) at org.jboss.as.server.deployment.module.VFSResourceLoader$2.run(VFSResourceLoader.java:127) at org.jboss.as.server.deployment.module.VFSResourceLoader$2.run(VFSResourceLoader.java:124) at java.security.AccessController.doPrivileged(Native Method) at org.jboss.as.server.deployment.module.VFSResourceLoader.getClassSpec(VFSResourceLoader.java:124) at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:252) at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:76) at org.jboss.modules.Module.loadModuleClass(Module.java:526) at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:189) // JBoss now fully responsible to load the class at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:444) // Unchecked since using JDK 1.7 e.g. tagged as “safe” JDK at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:432) at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:374) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:119) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:186) at org.jboss.tools.examples.rest.MemberResourceRESTService.AppCLFailure(MemberResourceRESTService.java:196) at org.jboss.tools.examples.rest.MemberResourceRESTService$Proxy$_$$_WeldClientProxy.AppCLFailure(Unknown Source) at sun.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ……………….

上面的執(zhí)行堆棧跟蹤非常揭示:

  • 由于未檢測到Java類名稱是Java系統(tǒng)包的一部分,因此不會執(zhí)行ClassLoader委派,因此不會進(jìn)行同步。
  • 由于JBoss認(rèn)為JDK 1.7+是“安全的” JDK,因此使用了ConcurrentClassLoader .performLoadClassUnchecked()方法,而不觸發(fā)任何對象監(jiān)視器鎖定。
  • 沒有同步意味著不間斷的ClassNotFoundException錯誤不會觸發(fā)線程鎖爭用。

仍然需要注意的是,盡管在這種情況下JBoss在防止線程鎖爭用方面做得很出色,但是由于與過多的JAR文件搜索操作相關(guān)的IO開銷,重復(fù)的類加載嘗試仍會在一定程度上降低性能。加強(qiáng)了立即采取糾正措施的必要性。

最后的話

我希望您喜歡這篇文章,并且現(xiàn)在對由于過多的類加載操作而可能對性能產(chǎn)生的影響有了更好的了解。 盡管JDK 1.7和現(xiàn)代Java EE容器在類加載器相關(guān)的問題(例如死鎖和線程鎖爭用)上進(jìn)行了重大改進(jìn),但仍然存在潛在的問題場景。 因此,我強(qiáng)烈建議您密切監(jiān)視應(yīng)用程序的行為,記錄日志,并確保積極糾正與類加載器相關(guān)的錯誤,例如java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError 。

我期待您的意見,并請與Java類加載器分享您的故障排除經(jīng)驗。

參考: ClassNotFoundException:是否減慢了JVM的速度? 來自我們的JCG合作伙伴 Pierre Hugues Charbonneau,來自Java EE支持模式博客。

翻譯自: https://www.javacodegeeks.com/2014/04/classnotfoundexception-is-it-slowing-down-your-jvm.html

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的ClassNotFoundException:是否减慢了您的JVM?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。