本人摘自:https://github.com/oldratlee/useful-scripts/blob/master/docs/java.md#beer-show-busy-java-threadsshcss
用於快速排查Java
的CPU
性能問題(top us
值太高),自動查出運行的Java
進程中消耗CPU
多的線程,並打印出其線程棧,從而肯定致使性能問題的方法調用。
目前只支持Linux
。緣由是Mac
、Windows
的ps
命令不支持列出線程線程,更多信息參見#33,歡迎提供解法。html
PS,如何操做能夠參見@bluedavy的《分佈式Java應用》的【5.1.1 cpu消耗分析】一節,說得很詳細:java
top
命令找出有問題Java
進程及線程id
:
CPU
使用率排序Java
進程id
及其CPU
高的線程id
id
做爲參數,jstack
有問題的Java
進程id
成十六進制(能夠用printf %x 1234
)id
(能夠用grep
)查問題時,會要屢次這樣操做以肯定問題,上面過程太繁瑣太慢了。linux
show-busy-java-threads
# 從全部運行的Java進程中找出最消耗CPU的線程(缺省5個),打印出其線程棧 # 缺省會自動從全部的Java進程中找出最消耗CPU的線程,這樣用更方便 # 固然你能夠手動指定要分析的Java進程Id,以保證只會顯示出那個你關心的Java進程的信息 show-busy-java-threads -p <指定的Java進程Id> show-busy-java-threads -c <要顯示的線程棧數> show-busy-java-threads <重複執行的間隔秒數> [<重複執行的次數>] # 屢次執行;這2個參數的使用方式相似vmstat命令 show-busy-java-threads -a <輸出記錄到的文件> # 記錄到文件以方便回溯查看 ############################## # 注意: ############################## # 若是Java進程的用戶 與 執行腳本的當前用戶 不一樣,則jstack不了這個Java進程 # 爲了能切換到Java進程的用戶,須要加sudo來執行,便可以解決: sudo show-busy-java-threads show-busy-java-threads -s <指定jstack命令的全路徑> # 對於sudo方式的運行,JAVA_HOME環境變量不能傳遞給root, # 而root用戶每每沒有配置JAVA_HOME且不方便配置, # 顯式指定jstack命令的路徑就反而顯得更方便了 # -m選項:執行jstack命令時加上-m選項,顯示上Native的棧幀,通常應用排查不須要使用 show-busy-java-threads -m # -F選項:執行jstack命令時加上 -F 選項(若是直接jstack無響應時,用於強制jstack),通常狀況不須要使用 show-busy-java-threads -F # -l選項:執行jstack命令時加上 -l 選項,顯示上更多相關鎖的信息,通常狀況不須要使用 # 注意:和 -m -F 選項一塊兒使用時,可能會大大增長jstack操做的耗時 show-busy-java-threads -l # 幫助信息 $ show-busy-java-threads -h Usage: show-busy-java-threads [OPTION]... [delay [count]] Find out the highest cpu consumed threads of java, and print the stack of these threads. Example: show-busy-java-threads # show busy java threads info show-busy-java-threads 1 # update every 1 seconds, (stop by eg: CTRL+C) show-busy-java-threads 3 10 # update every 3 seconds, update 10 times Options: -p, --pid <java pid> find out the highest cpu consumed threads from the specifed java process, default from all java process. -c, --count <num> set the thread count to show, default is 5 -a, --append-file <file> specify the file to append output as log -s, --jstack-path <path> specify the path of jstack command -F, --force set jstack to force a thread dump use when jstack <pid> does not respond (process is hung) -m, --mix-native-frames set jstack to print both java and native frames (mixed mode) -l, --lock-info set jstack with long listing. Prints additional information about locks -h, --help display this help and exit delay the delay between updates in seconds count the number of updates delay/count arguments imitates style of vmstat command
$ show-busy-java-threads
[1] Busy(57.0%) thread(23355/0x5b3b) stack of java process(23269) under user(admin):
"pool-1-thread-1" prio=10 tid=0x000000005b5c5000 nid=0x5b3b runnable [0x000000004062c000] java.lang.Thread.State: RUNNABLE at java.text.DateFormat.format(DateFormat.java:316) at com.xxx.foo.services.common.DateFormatUtil.format(DateFormatUtil.java:41) at com.xxx.foo.shared.monitor.schedule.AppMonitorDataAvgScheduler.run(AppMonitorDataAvgScheduler.java:127) at com.xxx.foo.services.common.utils.AliTimer$2.run(AliTimer.java:128) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:662) [2] Busy(26.1%) thread(24018/0x5dd2) stack of java process(23269) under user(admin): "pool-1-thread-2" prio=10 tid=0x000000005a968800 nid=0x5dd2 runnable [0x00000000420e9000] java.lang.Thread.State: RUNNABLE at java.util.Arrays.copyOf(Arrays.java:2882) at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:572) at java.lang.StringBuffer.append(StringBuffer.java:320) - locked <0x00000007908d0030> (a java.lang.StringBuffer) at java.text.SimpleDateFormat.format(SimpleDateFormat.java:890) at java.text.SimpleDateFormat.format(SimpleDateFormat.java:869) at java.text.DateFormat.format(DateFormat.java:316) at com.xxx.foo.services.common.DateFormatUtil.format(DateFormatUtil.java:41) at com.xxx.foo.shared.monitor.schedule.AppMonitorDataAvgScheduler.run(AppMonitorDataAvgScheduler.java:126) at com.xxx.foo.services.common.utils.AliTimer$2.run(AliTimer.java:128) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) ...
上面的線程棧能夠看出,CPU
消耗最高的2個線程都在執行java.text.DateFormat.format
,業務代碼對應的方法是shared.monitor.schedule.AppMonitorDataAvgScheduler.run
。能夠基本肯定:android
AppMonitorDataAvgScheduler.run
調用DateFormat.format
次數比較頻繁。DateFormat.format
比較慢。(這個能夠由DateFormat.format
的實現肯定。)多執行幾回show-busy-java-threads
,若是上面狀況高几率出現,則能夠肯定上面的斷定。
由於調用越少代碼執行越快,則出如今線程棧的機率就越低。
腳本有自動屢次執行的功能,指定 重複執行的間隔秒數/重複執行的次數 參數。git
分析shared.monitor.schedule.AppMonitorDataAvgScheduler.run
實現邏輯和調用方式,以優化實現解決問題。github
JAVA_HOME
的判斷。 #15找出Java Lib
(Java
庫,即Jar
文件)或Class
目錄(類目錄)中的重複類。
全系統支持(Python
實現,安裝Python
便可),如Linux
、Mac
、Windows
。web
Java
開發的一個麻煩的問題是Jar
衝突(即多個版本的Jar
),或者說重複類。會出NoSuchMethod
等的問題,還不見得當時出問題。找出有重複類的Jar
,能夠防患未然。正則表達式
Libs
目錄,查找目錄下Jar
文件,收集Jar
文件中Class
文件以分析重複類。能夠指定多個Libs
目錄。Jar
文件,不會查找子目錄下Jar
文件。由於Libs
目錄通常不會用子目錄再放Jar
,這樣也避免把去查找不指望Jar
。-c
選項指定Class
目錄,直接收集這個目錄下的Class
文件以分析重複類。能夠指定多個Class
目錄。# 查找當前目錄下全部Jar中的重複類 show-duplicate-java-classes # 查找多個指定目錄下全部Jar中的重複類 show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2 # 查找多個指定Class目錄下的重複類。 Class目錄 經過 -c 選項指定 show-duplicate-java-classes -c path/to/class_dir1 -c /path/to/class_dir2 # 查找指定Class目錄和指定目錄下全部Jar中的重複類的Jar show-duplicate-java-classes path/to/lib_dir1 /path/to/lib_dir2 -c path/to/class_dir1 -c path/to/class_dir2 # 幫助信息 $ show-duplicate-java-classes -h Usage: show-duplicate-java-classes [-c class-dir1 [-c class-dir2] ...] [lib-dir1|jar-file1 [lib-dir2|jar-file2] ...] Options: -h, --help show this help message and exit -c CLASS_DIRS, --class-dir=CLASS_DIRS add class dir
JDK
開發場景使用說明以Maven
做爲構建工程示意過程。spring
# 在項目模塊目錄下執行,拷貝依賴Jar到目錄target/dependency下 $ mvn dependency:copy-dependencies -DincludeScope=runtime ... # 檢查重複類 $ show-duplicate-java-classes target/dependency ...
Web
工程對於Web
工程,即war
maven
模塊,會打包生成war
文件。
# 在war模塊目錄下執行,生成war文件 $ mvn install ... # 解壓war文件,war文件中包含了應用的依賴的Jar文件 $ unzip target/*.war -d target/war ... # 檢查重複類 $ show-duplicate-java-classes -c target/war/WEB-INF/classes target/war/WEB-INF/lib ...
Android
開發場景使用說明Android
開發,有重複類在編譯打包時會報[Dex Loader] Unable to execute dex: Multiple dex files define Lorg/foo/xxx/Yyy
。
但只會給出一個重複類名,若是重複類比較多時,上面打包/報錯/排查會要進行屢次,而Android
的打包比較費時,這個過程比較麻煩,但願能夠一次把全部重複類都列出來,一塊兒排查掉。
以Gradle
做爲構建工程示意過程。
在App
的build.gradle
中添加拷貝庫到目錄build/dependencies
下。
task copyDependencies(type: Copy) { def dest = new File(buildDir, "dependencies") // clean dir dest.deleteDir() dest.mkdirs() // fill dir with dependencies from configurations.compile into dest }
# 拷貝依賴 $ ./gradlew app:copyDependencies ... # 檢查重複類 $ show-duplicate-java-classes app/build/dependencies ...
$ show-duplicate-java-classes WEB-INF/lib
COOL! No duplicate classes found! ================================================================================ class paths to find: ================================================================================ 1 : WEB-INF/lib/sourceforge.spring.modules.context-2.5.6.SEC02.jar 2 : WEB-INF/lib/misc.htmlparser-0.0.0.jar 3 : WEB-INF/lib/normandy.client-1.0.2.jar ... $ show-duplicate-java-classes -c WEB-INF/classes WEB-INF/lib Found duplicate classes in below class path: 1 (293@2): WEB-INF/lib/sourceforge.spring-2.5.6.SEC02.jar WEB-INF/lib/sourceforge.spring.modules.orm-2.5.6.SEC02.jar 2 (2@3): WEB-INF/lib/servlet-api-3.0-alpha-1.jar WEB-INF/lib/jsp-api-2.1-rev-1.jar WEB-INF/lib/jstl-api-1.2-rev-1.jar 3 (104@2): WEB-INF/lib/commons-io-2.2.jar WEB-INF/lib/jakarta.commons.io-2.0.jar 4 (6@3): WEB-INF/lib/jakarta.commons.logging-1.1.jar WEB-INF/lib/commons-logging-1.1.1.jar WEB-INF/lib/org.slf4j.jcl104-over-slf4j-1.5.6.jar 5 (344@2): WEB-INF/lib/sourceforge.spring-2.5.6.SEC02.jar WEB-INF/lib/sourceforge.spring.modules.context-2.5.6.SEC02.jar ... ================================================================================ Duplicate classes detail info: ================================================================================ 1 (293@2): WEB-INF/lib/sourceforge.spring-2.5.6.SEC02.jar WEB-INF/lib/sourceforge.spring.modules.orm-2.5.6.SEC02.jar 1 org/springframework/orm/toplink/TopLinkTemplate$13.class 2 org/springframework/orm/hibernate3/HibernateTemplate$24.class 3 org/springframework/orm/jpa/vendor/HibernateJpaDialect.class 4 org/springframework/orm/hibernate3/TypeDefinitionBean.class 5 org/springframework/orm/hibernate3/SessionHolder.class ... 2 (2@3): WEB-INF/lib/servlet-api-3.0-alpha-1.jar WEB-INF/lib/jsp-api-2.1-rev-1.jar WEB-INF/lib/jstl-api-1.2-rev-1.jar 1 javax/servlet/ServletException.class 2 javax/servlet/ServletContext.class 3 (104@2): WEB-INF/lib/commons-io-2.2.jar WEB-INF/lib/jakarta.commons.io-2.0.jar 1 org/apache/commons/io/input/ProxyReader.class 2 org/apache/commons/io/output/FileWriterWithEncoding.class 3 org/apache/commons/io/output/TaggedOutputStream.class 4 org/apache/commons/io/filefilter/NotFileFilter.class 5 org/apache/commons/io/filefilter/TrueFileFilter.class ... ... ================================================================================ class paths to find: ================================================================================ 1 : WEB-INF/lib/sourceforge.spring.modules.context-2.5.6.SEC02.jar 2 : WEB-INF/lib/misc.htmlparser-0.0.0.jar 3 : WEB-INF/lib/normandy.client-1.0.2.jar 4 : WEB-INF/lib/xml.xmlgraphics__batik-css-1.7.jar-1.7.jar 5 : WEB-INF/lib/jakarta.ecs-1.4.2.jar ...
tgic提供此腳本。友情貢獻者的連接commandlinefu.cn|微博linux命令行精選
在當前目錄下全部jar
文件裏,查找類或資源文件。
支持Linux
、Mac
、Windows
(cygwin
、MSSYS
)。
# 在當前目錄下全部`jar`文件裏,查找類或資源文件。 find-in-jars 'log4j\.properties' find-in-jars 'log4j\.xml$' find-in-jars log4j\\.xml$ # 和上面命令同樣,Shell轉義的不一樣寫法而已 find-in-jars 'log4j(\.properties|\.xml)$' # -d選項 指定 查找目錄(覆蓋缺省的當前目錄) find-in-jars 'log4j\.properties$' -d /path/to/find/directory # 支持多個查找目錄 find-in-jars 'log4j\.properties' -d /path/to/find/directory1 -d /path/to/find/directory2 # 幫助信息 $ find-in-jars -h Usage: find-in-jars [OPTION]... PATTERN Find file in the jar files under specified directory(recursive, include subdirectory). The pattern default is *extended* regex. Example: find-in-jars 'log4j\.properties' find-in-jars '^log4j(\.properties|\.xml)$' # search file log4j.properties/log4j.xml at zip root find-in-jars 'log4j\.properties$' -d /path/to/find/directory find-in-jars 'log4j\.properties' -d /path/to/find/dir1 -d /path/to/find/dir2 Options: -d, --dir the directory that find jar files, default is current directory. this option can specify multiply times to find in multiply directory. -E, --extended-regexp PATTERN is an extended regular expression (*default*) -F, --fixed-strings PATTERN is a set of newline-separated strings -G, --basic-regexp PATTERN is a basic regular expression -P, --perl-regexp PATTERN is a Perl regular expression -i, --ignore-case ignore case distinctions -h, --help display this help and exit
注意,Pattern缺省是grep
的 擴展正則表達式。
# 在當前目錄下的全部Jar文件中,查找出 log4j.properties文件 $ find-in-jars 'log4j\.properties$' ./hadoop-core-0.20.2-cdh3u3.jar!log4j.properties # 查找出 以Service結尾的類 $ ./find-in-jars 'Service.class$' ./WEB-INF/libs/spring-2.5.6.SEC03.jar!org/springframework/stereotype/Service.class ./rpc-benchmark-0.0.1-SNAPSHOT.jar!com/taobao/rpc/benchmark/service/HelloService.class ...... # 在指定的多個目錄的Jar文件中,查找出 properties文件 $ find-in-jars '\.properties$' -d ../WEB-INF/lib -d ../deploy/lib | grep -v '/pom\.properties$' ../WEB-INF/lib/aspectjtools-1.6.2.jar!org/aspectj/ajdt/ajc/messages.properties ../WEB-INF/lib/aspectjtools-1.6.2.jar!org/aspectj/ajdt/internal/compiler/parser/readableNames.properties ../WEB-INF/lib/aspectjweaver-1.8.8.jar!org/aspectj/weaver/XlintDefault.properties ../WEB-INF/lib/aspectjweaver-1.8.8.jar!org/aspectj/weaver/weaver-messages.properties ../deploy/lib/groovy-all-1.1-rc-1.jar!groovy/ui/InteractiveShell.properties ../deploy/lib/groovy-all-1.1-rc-1.jar!org/codehaus/groovy/tools/shell/CommandAlias.properties ../deploy/lib/httpcore-4.3.3.jar!org/apache/http/version.properties ../deploy/lib/httpmime-4.2.2.jar!org/apache/http/entity/mime/version.properties ../deploy/lib/javax.servlet-api-3.0.1.jar!javax/servlet/LocalStrings_fr.properties ../deploy/lib/javax.servlet-api-3.0.1.jar!javax/servlet/http/LocalStrings_es.properties ......