簡體   English   中英

使用不同的java應用程序導出選項的奇怪行為

[英]Strange behavior with different java application export option

我有java服務器應用程序,它使用很多庫(netty,guava等)。 我總是將此應用程序導出為單個.jar。 當我在Eclipse中運行應用程序時,我沒有任何問題。 但是,如果我在控制台(Windows或Ubuntu,無關緊要)啟動應用程序,我有一個奇怪的問題:通過套接字的所有連接進程持續太長時間。 例如,通過HttpAsync或其他人(rabbitmq連接等)的簡單http連接持續1-2分鍾。 但連接完成后,數據發送/接收速度很快。 我無法弄清楚是什么問題。 如前所述,我使用Eclipse進行開發。

如您所知,您可以導出項目3方式(在Eclipse中):

  1. 將所需的庫提取到JAR中。
  2. 將所需的庫打包到JAR中。
  3. 將所需的庫復制到JAR旁邊的子文件夾中。

所以,當我使用2選項時,我遇到了問題。 當我切換到3d選項(main .jar附近的文件夾中的所有.jars)時,問題就解決了。

通常情況下,2和3選項之間沒有太大區別(2個所有.jars只在一個jar內)。 我認為這是從jar開始在執行時加載新類所需的額外時間的原因。 但問題不僅發生在開始,而且發生在所有新連接上。

有人可以解釋這種行為嗎?

UPD: Eclipse Luna。 無論我使用什么操作系統(Windows,或Ubuntu),甚至無關緊要jvm(嘗試使用不同的Oracle jdk,甚至嘗試打開jdk)。

這一切都討論了在從JAR v / s解壓縮到JAR時的性能差異以及從從控制台運行的Eclipse v / s運行時的性能差異。

打包到JAR中的JAR v / s中的性能差異:

將所需的庫提取到JAR中:

它能做什么:
在此選項中,Eclipse將從引用的JAR和包中提取所有類到生成的JAR中。

如果打開JAR,那么您會發現沒有打包引用的JAR,但所有引用的JAR類都按照包結構排列,然后在根級別打包在JAR中。 “將所需包裝到jar文件中”相比,這帶來了性能上的關鍵差異,其中還存在運行時解析和在內存中加載JAR等成本。

當通過Eclipse導出為JAR時,如果關注性能,則最好選擇。 這也是可擴展的選項,因為您可以發送此JAR

MANIFEST.MF這個文件中要注意的主要是你的主要課程。 當您運行JAR時,您將直接運行所需的類。

Main-Class: com.my.jar.TestSSL


將所需的庫打包到JAR中:

它能做什么:
在這個選項中,Eclipse將:

  • 將所有引用的JAR打包到生成的JAR中。
  • 通過org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader使用Eclipse的JAR加載機制,你也可以在你生成的JAR中看到org.eclipse.jdt.internal.jarinjarloader包,這個包就在生成的JAR的根目錄下。

當然這當你選擇這個選項時會產生額外的成本,因為當你運行JAR時,你不是主類被執行,而是執行JarRsrcLoader ,這將加載你的主類和其他庫,以及所有引用的庫包裝好了。 請參閱下面的MANIFEST.MF部分

MANIFEST.MF這個文件中要注意的主要是你的主要課程。 當您運行JAR時, JarRsrcLoader將運行並將繼續工作。

Rsrc-Main-Class: com.cgi.tmi.TestSSL
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader


現在對於最后一個Eclipse導出選項 - “將所需的庫復制到JAR旁邊的子文件夾” ,我認為這不是一個非常可擴展的解決方案,因為這會強制您的文件系統依賴,所以我想不要這樣做。

從運行控制台的Eclipse v / s運行時的性能差異:

當你從Eclipse運行應用程序時,它很安靜,類似於第一個導出選項,其中Eclipse不需要在運行時解析和加載JAR。
然而,這是一個非常簡單的觀點,關鍵是考慮Eclipse JAR導出選項1 v / s選項2。


最后的話:

  • 使用“將所需的庫提取到JAR”來導出JAR,您將看到實質性的性能提升。
    • 當您從控制台運行時,套接字連接很長時間是非常不可能的,因為JVM運行代碼然后在從Eclipse和控制台運行時具有相同或非常可比的性能(在這兩種情況下考慮相同的Java版本)。 你可能會因為打包的JAR性能而感覺到。 嘗試提取JAR,你應該沒問題。
  • 另外,請考慮您正在執行的日志記錄量。 在運行時,根據配置,Eclipse可能會掩蓋大量日志記錄,從而節省您的i / o時間。
  • 理解如何從JAR類路徑訪問類 ,這就像從JAR引用類時的額外計算成本。

由於我們不知道JAR的確切結構,因此這是一個更一般的解釋(假設您使用java -jar your_app.jar運行應用程序)。

case 將所需的庫復制到JAR旁邊的子文件夾中。

  • 如果需要加載類,則類加載器(在運行時JAR之后)首先檢查your_app.jar以查找所需的類
  • 如果找不到該類,則遍歷子文件夾中的所有JAR文件
  • 所有JAR文件都可以保存在文件系統緩存中以供進一步閱讀

case將所需的庫打包到JAR中

  • 如果需要加載類,則Eclipse類加載器JarRsrcLoader(在運行時JAR之后)首先檢查your_app.jar以查找所需的類
  • 如果找不到類,則遍歷所有嵌入的JAR文件,這意味着首先需要從your_app.jar解壓縮才能讀取內容
  • 提取的嵌入式JAR文件不會保存在文件系統緩存中以供進一步讀取(因為它們不是文件系統中的文件)

如果你有更多的hugh嵌入式庫JAR,這可能會導致類加載速度變慢(但只是第一次類加載器加載一個類)。

如果你比較的是outpout,你可以看到類加載的差異

java -verbose:class -jar your_app_external_library_jars.jar

java -verbose:class -jar your_app_embedded_library_jars.jar

通過為每個JAR文件(例如your_app.jar和嵌入式庫JAR)生成INDEX.LIST文件,可以提高性能。

這是因為當你采用“超級罐”方法時,一些元數據可能會丟失。

這只是一個例子,但是如果你下載這個這個 ,看看罐子里。 在同一META-INF文件夾中有一些具有相同名稱的文件。

這些文件可能很重要,當eclipse為你重新打包時,他可能不會在合並這些文件方面做得不錯。

這就是你可能會發生的事情。

在第二種方法中,您在main.jar中擁有所有依賴項jar。 因此除非需要,否則它不會加載任何依賴jar。 然而,在第3個選項的情況下,你的main.jar和其他依賴jar是獨立的(不像第二種方式),因此可以加載連接並且可用。

嘗試通過操作依賴jar來添加日志語句或syso以查看此工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM