普通Java程式設計師學習使用的6個JDK內建工具

2021-02-13 Oracle學習中心

有些博客認為「每個小孩都應該學習編程」,「你認為學數學只是玩玩而已?如果你有看過我的HTML5調試器的話,你會發現我是一個程式設計師,但我做的工作遠不止數學這些」。 上面兩者都同意一個觀點,軟體工程不只是用計算機語言寫的一些隻言片語。軟體解決的問題詮釋了程式設計師的價值。

解決問題的最終進展來自科學、強化清晰的頭腦和我們一路以來使用的工具。

你有沒有留意過那些 JDK 安裝附帶的工具?既然那些大牛同意把那些工具加到 JDK 裡,應該是有用的。

因此,在這篇文章裡,我挑了幾個 Hotspot 標準安裝後可用的小工具來介紹。我們決定忽略那些安全相關的和各種遠程方法調用(RMI)、applets、web-start、web-services 工具。讓我們把焦點放在那些普通開發者開發一般應用過程中可能有用的工具。注意,如果你只是對命令行工具感興趣,而不僅僅是Java相關的工具,這裡介紹了 5 個非常有用的命令行工具。

再次重申,下面雖然不是 JDK 工具完整列表,但是我們想給你一個精華版本。下面是你用這些命令可以完成的真正有用的事情。

0、javap

你可以給 javap(Java Class文件反編譯器)傳遞這些有用的參數:

比如在著名的「你真的懂 Classloader 嗎?」演講裡,當出現 NoSuchMethodException 錯誤時,我們可以執行以下命令來調查這個類究竟有哪些成員方法和獲取這個類所有想找的信息:

javap -l -c -p Util2

當調試類內部信息或者研究隨機字節碼順序時,javap 非常有用。

1、jjs

jjs命令可以啟動一個 JavaScript 命令終端,你可以把它當做計算器或者用隨機的JS字符串測試JS的古怪用法。不要讓另一個 JavaScript 謎題讓你措手不及!

哈,看到剛剛發生了什麼了麼?但是 JavaScript 是另一個話題,只需要知道即使沒有 node.js 或瀏覽器你也可以用jjs知道JS是怎麼工作的。

2、jhat

Java堆分析工具(jhat)正如它名字描述的那樣:分析dump堆信息。在下面的小例子裡,我們構造了一個 OutOfMemoryError ,然後給這個 java 進程指定 -XX:+HeapDumpOnOutOfMemoryError ,這樣運行時就會產生一個 dump 文件供我們分析。

public class OhMyMemory { private static Map map = new HashMap<>(); public static void main(String[] args) { Runtime.getRuntime().addShutdownHook( new Thread() { @Override public void run() { System.out.println("We have accumulated " + map.size() + " entries"); } } ); for(int i = 0; ;i++) { map.put(Integer.toBinaryString(i), i); } }}

產生一個 OutOfMemoryError 很簡單(大部分情況下我們無意為之),我們只要不斷地製造不讓垃圾回收器起作用就可以了。

運行這段代碼會產生如下輸出:

org.shelajev.throwaway.jdktools.OhMyMemoryjava.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid5644.hprof ...Heap dump file created [73169721 bytes in 0.645 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.HashMap.resize(HashMap.java:703)at java.util.HashMap.putVal(HashMap.java:662)at java.util.HashMap.put(HashMap.java:611)at org.shelajev.throwaway.jdktools.OhMyMemory.main(OhMyMemory.java:24)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:483)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)We have accumulated 393217 entries

不錯,我們現在有一個可供分析的文件了。我們對這個文件執行jhat開始進行分析,jhat 會分析這個文件開啟一個 http 伺服器供我們查看結果。

$ jhat java_pid5644.hprofReading from java_pid5644.hprof...Dump file created Thu Aug 14 14:48:19 EEST 2014Snapshot read, resolving...Resolving 1581103 objects...Chasing references, expect 316 dots...Eliminating duplicate references...Snapshot resolved.Started HTTP server on port 7000Server is ready.

可以通過訪問 http://localhost:7000 來查看 dump 的數據。

在那個頁面我們可以通過堆信息的柱狀圖了解究竟是什麼耗盡了內存。

現在我們可以清晰地看到擁有 393567 結點的 HashMap 就是導致程序崩潰的元兇。雖然有更多可以檢查內存分布使用情況和堆分析的工具,但是jhat是內置的,是分析的一個好的開端。

3、jmap

jmap 是一個內存映射工具,它提供了另外一種不需要引發 OutOfMemoryErrors 就可以獲取堆 dump 文件的方法。我們稍微修改一下上面的程序看一下效果。

public class OhMyMemory { private static Map map = new HashMap<>(); public static void main(String[] args) { Runtime.getRuntime().addShutdownHook( new Thread() { @Override public void run() { try { System.out.println("Enter something, so I'll release the process"); System.in.read(); System.out.println("We have accumulated " + map.size() + " entries"); } catch (IOException e) { e.printStackTrace(); } } } ); for(int i = 0; i < 10000 ;i++) { map.put(Integer.toBinaryString(i), i); } }}

注意,現在我們不要消耗大量的內存,只是比較早結束並在進程關閉鉤子裡等待不讓 JVM 退出。這樣就允許我們用 jmap 連接這個進程獲取珍貴的內存 dump。

因此你可以用 jmap 的兩個功能來實現,獲取堆統計信息和觸發一個堆 dump。因此,當執行:

jmap -heap 1354(這裡 1354 是上面程序運行的進程號),就可以獲取一個很好的內存使用統計信息:

$ jmap -heap 1354 Attaching to process ID 1354, please wait...Debugger attached successfully.Server compiler detected.JVM version is 25.0-b70using thread-local object allocation.Parallel GC with 4 thread(s)Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 67108864 (64.0MB) NewSize = 1572864 (1.5MB) MaxNewSize = 22020096 (21.0MB) OldSize = 45088768 (43.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB)Heap Usage:PS Young GenerationEden Space: capacity = 1048576 (1.0MB) used = 628184 (0.5990829467773438MB) free = 420392 (0.40091705322265625MB) 59.908294677734375% usedFrom Space: capacity = 524288 (0.5MB) used = 491568 (0.4687957763671875MB) free = 32720 (0.0312042236328125MB) 93.7591552734375% usedTo Space: capacity = 524288 (0.5MB) used = 0 (0.0MB) free = 524288 (0.5MB) 0.0% usedPS Old Generation capacity = 45088768 (43.0MB) used = 884736 (0.84375MB) free = 44204032 (42.15625MB) 1.9622093023255813% used981 interned Strings occupying 64824 bytes.

$ jmap -dump:live,format=b,file=heap.bin 1354 Dumping heap to /Users/shelajev/workspace_idea/throwaway/heap.bin ...Heap dump file created

jmap 還可以簡單地觸發當前堆 dump,之後可以隨意進行分析。你可以像下面例子中的那樣,傳一個 -dump 參數給 jmap。

現在有了 dump 得到的文件 heap.bin,就可以用你喜歡的內存分析工具來分析。

4、jps

jps 是顯示 Java 程序系統進程(PID)最常用的工具。它與平臺無關,非常好用。想像一下我們啟動了上面的程序,然後想用 jmap 連接它。這個時候我們需要程序的 PID,jps 正好的派上用場。

$ jps -mlv5911 com.intellij.rt.execution.application.AppMain org.shelajev.throwaway.jdktools.OhMyMemory -Xmx64m -Didea.launcher.port=7535 -Didea.launcher.bin.path=/Applications/IntelliJ IDEA 14 EAP.app/Contents/bin -Dfile.encoding=UTF-85544 -Dfile.encoding=UTF-8 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -Djsse.enableSNIExtension=false -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -XX:+HeapDumpOnOutOfMemoryError -Xverify:none -Xbootclasspath/a:../lib/boot.jar -Xms128m -Xmx750m -XX:MaxPermSize=350m -XX:ReservedCodeCacheSize=225m -XX:+UseCompressedOops -agentlib:yjpagent=probe_disable=*,disablealloc,disabletracing,onlylocal,disableexceptiontelemetry,delay=10000,sessionname=IntelliJIdea14 -Didea.java.redist=NoJavaDistribution -Didea.home.path=/Applications/IntelliJ IDEA 14 EAP.app/Contents -Didea.paths.selector=IntelliJIdea145930 sun.tools.jps.Jps -mlvV -Dapplication.home=/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home -Xms8m

我們發現大多數情況下,「-mlv」 參數組合起來最好用。它會列印main方法的參數、完整包名、JVM 相關參數。這樣你就可以在一大堆相似的進程中找到你想要的那個。

現在有了 dump 得到的文件 heap.bin,就可以用你喜歡的內存分析工具來分析。

5、jstack

jstack 是一個生成指定 JVM 進程的線程堆棧工具。當你程序一直在那裡轉圈圈,而你想找到線程到底做了什麼導致死鎖,那麼 jstack 最適合。

jstack 只有幾個參數選項,如果你拿不準,把它們都加上。如果後面發現有些信息對你意義不大時可以調整參數限制它的輸出。

-F 選項可以用來強制 dump,這在進程掛起時非常有用,-I 選項可以列印同步和鎖的信息。

$ jstack -F -l 9153Attaching to process ID 9153, please wait...Debugger attached successfully.Server compiler detected.JVM version is 25.0-b70Deadlock Detection:No deadlocks found.….

上面的輸出雖然看起來簡單,但是它包含了每個線程的狀態和它當前的堆棧的信息。

jstack 非常有用,我們在日常工作中使用非常頻繁,特別是我們負責啟動停止應用伺服器的測試引擎。測試工作往往不順利,jstack 可以讓我們知道 JVM 內部的運行狀態且沒有什麼負面的影響。

— Neeme Praks(ZeroTurnaround資深產品工程師)

還有其它的嗎?

今天我們介紹了 JDK 發行預裝的超棒工具。相信我,將來某天你肯定會用到它們中的一些。所以,如果你有時間,你可以翻一翻它們的官方文檔。

試著在不同的場景使用並愛上它們。

如果你想學一些超棒的非 JDK 附帶的工具,可以看看 JRebel ,它可以讓你馬上看到代碼的改動效果,還可以看到我們新的產品 XRebel ,它可以像X光眼鏡一樣掃描你的 web 應用。

如果你知道開發最佳實踐中至關重要的小工具,在本文末尾發表評論或者在 twitter上@shelajev 分享一下這個工具的細節。

Bonus Section: References

獎勵環節:參考

下面是一個更加完整的 JDK 工具可用列表。雖然這不是一個完整的列表,為了節省篇幅,我們省掉了加密、web-services 相關的工具等。謝謝 manpagez.com 提供的資源。

jar — 一個創建和管理 jar 文件的工具。

java — Java 應用啟動器。在這篇文章裡,開發和部署都是用的這個啟動器。

javac — Java 編譯器。

javadoc — API 文檔生成器。

javah — native 本地方法中用於生成 C 語言頭文件和源文件。

javap — class 文件反編譯器。

jcmd — JVM 命令行診斷工具,可發送診斷命令請求到 JVM 中。

jconsole — 一個兼容 JMX 的監控 JVM 的圖形化工具。可以監控本地和遠程 JVM,也可以監控和管理單獨的一個應用。

jdb — Java 調試器。

jps — JVM 進程查看工具,列出了系統運行的所有 hotspot JVM 進程。

jstat — JVM 狀態監控工具。它可以收集和列印指定的 JVM 進程性能狀態。

jhat — 堆 dump 信息的瀏覽器,啟動一個 web 伺服器來顯示你用諸如 jmap -dump 得到的堆 dump 信息。

jmap — Java 內存映射工具,列印指定進程、核心文件、遠程調試伺服器共享內存映射或者堆內存詳細信息。

jsadebugd — Java 服務調試守護進程—依附到一個 Java 進程或核心文件並且擔當一個調試伺服器的作用。

jstack —Java 堆棧信息工具——列印指定進程或核心文件或者遠程調試伺服器的線程堆棧。

jjs — 運行 Nashorn 命令行腳本 shell。

jrunscript — Java 腳本運行工具。不過你要心裡有數,這實際上是一個還沒支持的測試功能。未來的 JDK 版本裡面可能會移除它。

希望上面的內容對你們有幫助,你可以在 twitter 上 @ shelajev留下你寶貴的評論。如果你知道一些我沒有提及的重要工具,請讓我知道。

相關焦點

  • 如何使Java程式設計師擁有高效率的開發環境
    如何使Java程式設計師擁有高效率的開發環境 作為一名程式設計師,好的開發環境可以提升你的工作效率,事半功倍。那麼一名Java程式設計師應該擁有什麼樣的開發工具呢。
  • JAVA工具JDK安裝配置詳解
    學習Java,在自己的電腦上安裝Java的開發工具包JDK是必須的。安裝完成後需要進行一系列的手動配置環境,下面介紹如何進行JDK的安裝與配置1.進入JDK的官方網站下載相關的JDK安裝工具包。選擇下載的對應系統的安裝包2.完成下載安裝工具包後,雙擊安裝文件開始按照安裝嚮導進行安裝。3.在安裝到目標文件夾的界面中可以進行安裝到的目錄位置進行修改,可以根據各自的需求是否進行修改。如果無需修改可以採取默認的設置。點擊「下一步」進行安裝。
  • JAVA入門:從什麼是JAVA到編寫第一個java程序只需看這一篇
    因為有了JVM即java虛擬機,同一個Java 程序在三個不同的作業系統中都可以執行。這樣就實現了Java 程序的跨平臺性。java的跨平臺性是java能夠經久不衰的保證!JRE是個運行環境,JDK是個開發環境。因此寫Java程序的時候需要JDK,而運行Java程序的時候就需要JRE。
  • 阿里排查Java問題工具清單!
    /ldb/ {print}' f.txt  #不匹配ldbawk '/ldb/ && /LISTEN/ {print}' f.txt   #匹配ldb和LISTENawk '$5 ~ /ldb/ {print}' f.txt #第五列匹配ldb3 內建變量
  • 如何在Windows10系統中配置java的JDK環境
    今天給大家分享一下如何在Windows10系統中配置java的JDK環境。操作步驟如下:1.下載好 jdk 的安裝文件,我下載的是 jdk-10.0.1_windows-x64_bin.exe 這個版本的安裝文件;2.使用滑鼠雙擊該exe文件,該exe文件會運行安裝界面,截圖如下:3.安裝程序自動執行,界面如下:
  • 一份超詳細的 Java 問題排查工具單
    /ldb/ {print}' f.txt  #不匹配ldbawk '/ldb/ && /LISTEN/ {print}' f.txt   #匹配ldb和LISTENawk '$5 ~ /ldb/ {print}' f.txt #第五列匹配ldb3 內建變量
  • 第一天 Java基礎入門【悟空教程】
    4.3 程序編寫我們在整個Java學習階段均是在學習如何完成軟體編寫,由於到目前為止,沒有學習任何語法,所以在HelloWorld案例當中,我們直接使用模板代碼,完成編寫過程。程序的編寫過程與寫文檔類似,只是文檔是.txt文件,其內容為文字。Java程式設計師編寫的代碼又叫原始碼,是.java文件,其內容為符合Java語法的代碼。
  • 如何零基礎學好Java編程
    不同人考慮的問題不同,看法也不近相同,有人覺得Java完全可以自學沒有必要花錢學習,有人則認為,自學要學到什麼時候,能不能學會還是個問題,花費了時間還沒有效果,參加Java培訓的雖然會有支出,但成功率要比自學高不少。和一群小夥伴共同學習,也有學習的氣氛,也能更快的成長。
  • OpenJdk1.8筆記——java啟動流程
    Jdk中java的入口函數文件為openjdk\jdk\src\share\bin\main.c中的main方法(window上為WinMain),然後調用jdk8u-dev/jdk/src/share/bin/java.c的JLI_Launch方法,啟動一個jvm虛擬機;程序入口
  • 阿里內部都是這樣排查Java問題的,附工具單
    /ldb/ {print}' f.txt  #不匹配ldbawk '/ldb/ && /LISTEN/ {print}' f.txt   #匹配ldb和LISTENawk '$5 ~ /ldb/ {print}' f.txt #第五列匹配ldb3 內建變量
  • javaFX(二)-使用gradle+jdk14創建javafx程序
    在上一篇文章中,我們一起學習了jlink和jdk14的模塊化.
  • 學習java需要會哪些知識才能夠去應聘工作?
    打好基礎,以後學習就會一帆風順了。我們會先講解了Java程序的開發環境的搭建、編寫流程、工作原理等內容,接著學習有關Java編程的基本知識:包括變量、條件語句、循環語句、數組等內容,然後我們需要花幾天的時間學習什麼是面向對象。有了面向對象的基礎後,然後我們可以分別學習jdk提供的包的各個常用類的使用,包括lang包,io包,util包等等。接著學習線程,swing和網絡編程。
  • 最新的java(jdk+jre)完整安裝教程——附詳細步驟
    承接上文,本文將介紹java的安裝與配置,也就是jdk+jre的詳細安裝過程,以供大家參考、學習。>jdk+jre的安裝包命名一般都是這樣的:jdk-8u211-windows-x64.exe如果名稱中有bin字眼,表示只有jdk,沒有jre
  • Javaweb開發學習路線及Java三大框架分享
    Java在客戶端的應用有java applet,不過使用得很少,Java在伺服器端的應用非常的豐富,比如Servlet,JSP和第三方框架等等。Java技術對Web領域的發展注入了強大的動力。學習目標:Java程式設計師1: 熟悉jdk,jvm,eclipse,安裝於配置jdk2:熟悉並掌握java的基礎語法,類,抽象類,接口,內部類等概念3: java核心編程,如輸入輸出流,多線程,集合,XML,正則表達式等4:java
  • 程式設計師學Java要關注的6個網站,你知道幾個呢?
    學習Java開發除了使用Github、google、stackoverflow這三大程式設計師利器之外,還需要哪些網站呢?下面w3cschool給程式設計師小夥伴們分享java學習的6個網站:0、SourgeForgeSourgeForge是開源軟體開發者進行開發管理的集中式網站。有相當豐富的Java開放原始碼的著名的軟體。
  • 九年程式設計師推薦java書籍
    首先知乎爬取了以 #java# 為關鍵詞的三千本書,然後去除評分在7.5以下和評論人數少於150人次的書籍,最終得到以下篩選出以下結果.我將以評論人數排行榜&評分排行榜&綜合排行榜,進行書單的展示!並且你可以通過點擊書名,直接進入豆瓣查看該書的相關信息.
  • 阿里內部員工,排查Java問題常用的工具單
    文章內容做了部分刪減,主要刪減掉了其中只有阿里內部才能使用的工具的介紹,並刪減掉部分只有通過阿里內網才能訪問到的連結。 -1  1分鐘內修改過的文件pgmpgm -A -f vm-shopbase 'cat /home/admin/shopbase/logs/shopbase.log.2017-01-17|grep 2069861630'tsartsar是咱公司自己的採集工具。
  • Java程式設計師常用的10大構建工具
    近期,我做了一個調查,關於Java程式設計師使用的20幾個大數據工具。
  • jdk環境變量配置教程
    JDK是Java語言的開發工具包,學習Java語言或者JavaEE語言的時候,都需要安裝JDK軟體。如何配置java的JDK環境變量呢?下面,小編就來跟大家講解jdk環境變量配置的操作技巧。jdk環境變量配置教程1、右擊「我的電腦」,點擊屬性2、點擊:高級系統設置。3、在彈出的系統屬性中,選擇高級,在點擊環境變量。
  • JDK/Java 14 發布 - OSCHINA - 中文開源技術交流社區
    343:Packaging Tool (Incubator)打包工具(孵化階段)創建一個用於打包獨立 Java 應用程式的工具。switch 表達式擴展了 switch 語句,使其不僅可以作為語句(statement),還可以作為表達式(expression),並且兩種寫法都可以使用傳統的 switch 語法,或者使用簡化的「case L ->」模式匹配語法作用於不同範圍並控制執行流。這些更改將簡化日常編碼工作,並為 switch 中的模式匹配做好準備。