jmap:java內存映像工具
jmap用於生成堆轉儲快照,比較常用的option包括-heap,-histo,-dump
[root@localhost script]# jmap -h Usage: jmap [option] <pid> (to connect to running process) jmap [option] <executable <core> (to connect to a core file) jmap [option] [server_id@]<remote server IP or hostname> (to connect to remote debug server) where <option> is one of: <none> to print same info as Solaris pmap -heap to print java heap summary -histo[:live] to print histogram of java object heap; if the "live" suboption is specified, only count live objects -clstats to print class loader statistics -finalizerinfo to print information on objects awaiting finalization -dump:<dump-options> to dump java heap in hprof binary format dump-options: live dump only live objects; if not specified, all objects in the heap are dumped. format=b binary format file=<file> dump heap to <file> Example: jmap -dump:live,format=b,file=heap.bin <pid> -F force. Use with -dump:<dump-options> <pid> or -histo to force a heap dump or histogram when <pid> does not respond. The "live" suboption is not supported in this mode. -h | -help to print this help message -J<flag> to pass <flag> directly to the runtime system
java -heap [vmid],可以打印制定java虛擬機進程id的堆基本信息及使用情況,包括新生代大小、老年代大小、使用空間大小及比例。
jmap -histo [vmid],可以打印矩陣圖,可以看到java對象實例數量、大小、及具體是哪個對象。
jmap -dump:live,format=b,file=heap.bin <vmid>,可以生成一個heap.bin文件,從服務器上拿下來通過MAT工具進行分析,找到占用內存較高的對象,可以定位內存溢出的錯誤。
總體來說jmap命令操作簡單,但是用來優化系統和排查問題最常用的命令工具。
jstack:線程堆棧信息查看工具
jstack是jdk自帶的線程堆棧分析工具,使用該命令可以查看或導出 java 應用程序中線程堆棧信息。
[root@localhost script]# jstack -h Usage: jstack [-l] <pid> (to connect to running process) jstack -F [-m] [-l] <pid> (to connect to a hung process) jstack [-m] [-l] <executable> <core> (to connect to a core file) jstack [-m] [-l] [server_id@]<remote server IP or hostname> (to connect to a remote debug server) Options: -F to force a thread dump. Use when jstack <pid> does not respond (process is hung) -m to print both java and native frames (mixed mode) -l long listing. Prints additional information about locks -h or -help to print this help message
jstack可以用來排查CPU使用高、內存使用高的情況,最終定位到問題點。
通過top命令查看CPU(內存)占用高的進程ID,然后通過命令top -H -p <vmid>,定位到具體的線程號pid。
拿到pid后,轉為16進制,通過命令printf "%x\n" pid,拿到hexpid
然后通過jstack <vmid> | grep <hexpid> -A 30,最終定位到問題點。
jstack的使用例子:
我首先創建了一個很簡單的springboot的項目,然后提供了一個接口,接口的方法體中有個雙層循環(方法代碼見下面的mockdump),把該項目部署到linux服務器上,啟動后的進程id是73165,執行shell命令top -H -p 73165,然后通過瀏覽器訪問該方法。之后觀察到線程號73183的cpu使用率高達95%(見下圖),然后通過jstack查看線程堆棧信息(見最后的shell命令執行的結果),發現異常信息指向了64行雙層循環處,即定位到了代碼異常點。
@GetMapping("/mockdump") public String mockdump(String loopcount) throws InterruptedException, ExecutionException { log.info("===mockdump===start==="); for (int i = 0; i < Integer.parseInt(loopcount); i++) { ExecutorService executor = new ThreadPoolExecutor(2, 10, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); Future<String> f = executor.submit(new Callable<String>() { @Override public String call() throws Exception { log.info("===wolaile==="); return "wolaile"; } }); long result = 0l; for (int m = 0; m < 999999; m++) {//這個是當前類的第64行 for (int j = 0; j < 999999999; j++) { result = result + j; } } calllist.add(f.get()); } log.info("===mockdump===end==="); return "success"; }
[root@localhost ~]# printf "%x\n" 73183 11ddf [root@localhost ~]# jstack 73165 | grep 11ddf -A 30 "http-nio-8080-exec-1" #13 daemon prio=5 os_prio=0 tid=0x00007fb33cdd6000 nid=0x11ddf runnable [0x00007fb30e6e7000] java.lang.Thread.State: RUNNABLE at com.demo.incubator.swaggerdemo.controller.SwaggerDemoController.mockdump(SwaggerDemoController.java:64) 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:498) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:228) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)