Java web应用性能分析之【java进程问题分析工具】

Java web应用性能分析之【java进程问题分析概叙】-****博客

        前面大概讲了java进程问题分析流程,这里再小结一下分析工具,后面也会小结一下java进程问题分析定位。

1.分析工具

        1.1.linux命令工具

参考:Java web应用性能分析之【Linux服务器性能监控分析概叙】_web应用 cpu密集型-****博客

        1.2.jdk自带分析工具

        在JDK的bin目录下有很多命令行工具,各个工具的大小基本上都稳定在27kb左右,这个不是JDK开发团队刻意为之的,而是因为这些工具大多数是jdk\lib\tools.jar类库的一层薄包装而已,他们的主要功能代码是在tools类库中实现的。命令行工具的好处是:当应用程序部署到生产环境后,无论是直接接触物理服务器还是远程telnet到服务器上都会受到限制。而借助tools.jar类库里面的接口,我们可以直接在应用程序中实现功能强大的监控分析功能。

常用命令:

1、jps:JVM Process Status Tool,现实指定系统内所有的HotSpot虚拟机进程  查看本机java进程信息;jinfo:Configuration Info for Java,虚拟机配置信息, 查看jvm和系统参数信息。

2、jstack:Stack Track for java ,显示虚拟机线程快照,打印线程的栈信息,制作 线程dump文件

3、jmap: Memory map for java,生成虚拟机的内存转储快照,打印内存映射信息,制作 堆dump文件

4、jstat:JVM Statistics Monitoring Tool,用于收集Hotspot虚拟机各个方面的运行参数  ,gc性能监控工具。

5、jhat:内存分析工具,JVM heap Dunp Browser,用于分析heapdump文件,他会建立一个HTTP/HTML服务,让用户可通过浏览器查看 。

        jhat是sun提供的dump分析工具,上面讲过分析dump的工具还有MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer等,一般这个命令不太用到,是因为分析dump是个既耗时又耗机器资源的过程,第二个原因是这个工具比较简陋,没有MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer这些专业和强大。

        OpenJDK正在从JDK中废弃HPROF agent 并移除“jhat”工具。这是OpenJDK 9的Java SE平台借助Jigsaw实现模块化的结果,为了准备模块化,起草了多项提议(JEP),并且其中有很多都已经接近完成了。

6、jconsole:JConsole是一个基于JMX的GUI工具,用于连接正在运行的JVM,不过此JVM需要使用可管理的模式启动。简易的JVM可视化工具,其功能被jvisualvm替代。

7、jvisualvm:功能更强大的JVM可视化工具,

        jvisualVM所谓多合一虚拟机故障处理工具,有强大的插件扩展功能,通过安装插件扩展支持,jvisualVM可以做到:

        a、显示虚拟机进程及进程的配置和环境信息(jps,jinfo);

        b、监视应用程序CPU、GC、堆、方法区及线程的信息(jstat、jstack);

        c、dump及分析堆转储快照(jmap、jhat);

        d、方法级的程序性能分析,找出调用最多,运行时间最长的方法;

8、javap:查看字节码
9、jcmd:在JDK 1.7之后,新增了一个命令行工具jcmd。它是一个多功能工具,可以用来导出堆,查看java进程,导出线程信息,执行GC等。jcmd拥有jmap的大部分功能,Oracle官方建议使用jcmd代替jmap。

        1.3.arthas
  • 简介 | arthas
  • https://github.com/alibaba/arthas/issues/1892

        Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。

  Arthas可以帮助你解决:

  1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  5. 是否有一个全局视角来查看系统的运行状况?
  6. 有什么办法可以监控到 JVM 的实时运行状态?
  7. 怎么快速定位应用的热点,生成火焰图?
  8. 怎样直接从 JVM 内查找某个类的实例?

  Arthas 支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

        1.4.jprofile
  • YourKit是一个商业化的Java性能分析工具,提供了线程转储分析功能,可以快速定位线程问题,同时还提供了内存和CPU分析功能。
  • Java Profiler Features - YourKit

        JProfiler是一种Java性能分析器,可以帮助开发人员监视和优化Java应用程序的性能。它提供了一个功能强大的图形用户界面,使开发人员能够实时监视CPU使用情况、内存使用情况、线程和锁状态等信息。JProfiler还具有一些其他功能,例如分析内存泄漏、检测代码覆盖率、监视数据库连接等。

        使用JProfiler进行性能分析的一般步骤:

  1. 下载和安装JProfiler:从JProfiler官方网站下载JProfiler安装程序,并按照提示进行安装。
  2. 启动JProfiler:在开始菜单或桌面图标中找到JProfiler应用程序,并启动它。
  3. 创建会话:在JProfiler主界面中,单击“会话”按钮,并选择“创建”会话。在“会话设置”对话框中,选择要监视的Java进程或远程主机,并设置其他选项。
  4. 配置监视选项:在会话设置中,您可以选择要监视的Java应用程序选项。例如,您可以监视Java应用程序的CPU使用情况、内存使用情况、线程和锁状态等信息。
  5. 开始监视:在会话设置中,单击“开始”按钮,以开始监视Java应用程序。JProfiler将显示实时数据,并在出现问题时发出警告。
  6. 分析性能数据:在监视期间,您可以使用JProfiler的图形用户界面查看性能数据。您可以使用各种图表和工具来分析Java应用程序的性能,例如CPU使用率图表、内存使用情况图表、线程和锁状态等。
  7. 解决问题:根据分析的结果,您可以使用JProfiler提供的各种工具来解决性能问题。例如,您可以修复内存泄漏、优化代码、调整JVM参数等。
  8. 关闭会话:在解决问题后,您可以关闭JProfiler会话。如果您需要继续监视Java应用程序的性能,可以创建一个新的会话并重复上述步骤。

        总之,使用JProfiler可以帮助开发人员更好地了解Java应用程序的性能,并解决性能问题。但是,使用JProfiler需要一定的经验和技能,因此建议您先学习有关JProfiler的相关知识再使用它。

        1.5.jar包反编译工具

        下载地址:Java Decompiler

        JD-GUI和JAD是两个用于反编译Java字节码的工具。它们通常在以下情况下使用:

  1. 代码调试:当你需要调试Java代码时,可以使用JD-GUI将Java类反编译为可读的源代码,以便进行调试和分析。
  2. 代码分析:如果你需要对Java类进行深入的分析,例如了解代码结构、方法调用关系等,可以使用JD-GUI来反编译Java类,并查看反编译后的源代码。
  3. 代码重构:如果你需要修改现有的Java类,可以使用JD-GUI将Java类反编译为可读的源代码,然后进行修改。注意,反编译后的源代码可能不完全与原始源代码相同,因此在进行修改时需要谨慎。
  4. 辅助学习:如果你是一名Java初学者,可以通过JD-GUI和JAD反编译现有的Java类,了解Java类的结构和实现方式,从而加深对Java语言的理解。

        1.6.idea远程debug工具

        线上环境最好不要远程debug,因为debug时,会阻塞当前java进程的全部请求。大多数是在测试环境、开发环境。

 远程调试(对应IDEA功能:Remote JVM Debug)。远程调试使开发人员能够直接诊断服务器或其它线上进程上的问题,它提供了跟踪线上运行时错误并确定性能瓶颈和问题根源的方法,让你能够像在本地调试一样 Debug 远程服务器。

Ⅰ:Java的远程调试机制:
    Java虚拟机提供了远程调试机制,只需要在服务端启动时通过添加JVM参数开启调试服务端口,并且在
    客户端使用调试器连接到这个服务端口,就可以实现对远程JVM上程序的调试。
Ⅱ:IntelliJ IDEA远程调试的实现方式:
    IDEA利用Java的远程调试机制,在目标JVM上启用调试服务端口,并在IDEA上创建远程调试配置,连接
    到目标JVM上的调试服务端口,实现对远程程序的调试和控制。
Ⅲ:远程调试协议:
    在远程调试时,客户端和服务端之间通过远程调试协议进行通信。客户端会发送调试命令和断点信息到
    服务端口,服务端会执行调试命令并返回相应的结果,通过协议来实现客户端与服务端的交互。
Ⅳ:远程调试的工作原理:
    远程调试流程包括以下步骤:
        ①:启动远程 JVM 并配置调试服务端口;
        ②:在客户端创建远程调试配置,并连接到目标 JVM 上的调试服务端口;
        ③:在客户端设置断点和调试命令,并通过远程调试协议发送到服务端口;
        ④:服务端接收到命令后执行,并返回结果;
        ⑤:客户端收到结果后,根据调试命令和状态更新调试器界面。
Ⅴ:远程调试的优劣势:
    优势:可以直接在目标环境上调试代码,同时也可避免因操作系统等差异导致的问题;
    劣势:需要在目标环境上(服务端)开启调试服务端口,同时还需要在客户端设置调试器进行连接,非
    常繁琐。

1:服务端添加远程通道
要让远程服务器运行的代码支持远程调试,则服务端启动的时候必须加上特定的 JVM 参数,这些参数是:
    不同的JDK版本需要设置不同的配置:
        JDK 9 or later
            -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:9999
        JDK 5-8
            -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999
        JDK 1.4.x
            -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9999
        JDK 1.3.x or earlier
            -Xnoagent -Djava.compiler=NONE -Xdebug
            -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9999

这里的9999则是服务端开放的端口,后期客户端IDEA需要连接当前端口进行远程交互和调试。
但是我们需要注意的是,这个9999端口在服务端一定要放开防火墙或者安全组;
具体端口看项目需求;运行服务端jar包程序则如下(JDK 5-8版本):
    java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9999 
    ./SwaggerDemo-0.0.1-SNAPSHOT.jar > app.log &
2:客户端连接远程通道
设置Edit Configurations来配置信息

备注:服务器代码和本地代码必须一致,否则debug断点无效。

        1.7.springbootAdmin

        在SpringCloud项目中,部署一个SpringBootAdmin即可通过web页面查看各应用的request、堆、栈等信息。具体实现是SpringCloud的actoator。

        用于对 Spring Boot 应用的管理和监控。可以用来监控服务是否健康、是否在线、以及一些jvm数据等等。 Spring Boot Admin 分为服务端(spring-boot-admin-server)和客户端(spring-boot-admin-client),服务端和客户端之间采用 http 通讯方式实现数据交互;单体项目中需要整合 spring-boot-admin-client 才能让应用被监控。 在 SpringCloud 项目中,spring-boot-admin-server 是直接从注册中心抓取应用信息,不需要每个微服务应用整合 spring-boot-admin-client 就可以实现应用的管理和监控。

        主要的功能点有:

  1.                 显示应用程序的监控状态
  2.                 应用程序上下线监控
  3.                 查看 JVM,线程信息
  4.                 可视化的查看日志以及下载日志文件
  5.                 动态切换日志级别
  6.                 Http 请求信息跟踪

详细配置如下

	  <!--用于检查系统的监控情况-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>
  <!--Spring Boot Admin Server监控服务端-->
 <dependency>
     <groupId>de.codecentric</groupId>
     <artifactId>spring-boot-admin-starter-server</artifactId>
     <version>2.3.1</version>
 </dependency>
   <!--增加安全防护,防止别人随便进-->
 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
  </dependency>


启动类开启admin@EnableAdminServer


登录配置
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

    private final String adminContextPath;

    public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
        this.adminContextPath = adminServerProperties.getContextPath();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 登录成功处理类
        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        successHandler.setTargetUrlParameter("redirectTo");
        successHandler.setDefaultTargetUrl(adminContextPath + "/");

        http.authorizeRequests()
                //静态文件允许访问
                .antMatchers(adminContextPath + "/assets/**").permitAll()
                //登录页面允许访问
                .antMatchers(adminContextPath + "/login", "/css/**", "/js/**", "/image/*").permitAll()
                //其他所有请求需要登录
                .anyRequest().authenticated()
                .and()
                //登录页面配置,用于替换security默认页面
                .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
                //登出页面配置,用于替换security默认页面
                .logout().logoutUrl(adminContextPath + "/logout").and()
                .httpBasic().and()
                .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .ignoringAntMatchers(
                        "/instances",
                        "/actuator/**"
                );
    }
}


yml配置
server:
  port: 9111
spring:
  boot:
    admin:
      ui:
        title: HMB服务监控中心
      client:
        instance:
          metadata:
            tags:
              environment: local
         #要获取的client的端点信息
      probed-endpoints: health,env,metrics,httptrace:trace,threaddump:dump,jolokia,info,logfile,refresh,flyway,liquibase,heapdump,loggers,auditevents
      monitor: # 监控发送请求的超时时间
        default-timeout: 20000
  security: # 设置账号密码
    user:
      name: admin
      password: admin
# 服务端点详细监控信息
management:   
  trace:
    http:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      show-details: always


启动项目
访问 http://ip:端口,

如我的http://localhost:9111,账号密码都是admin(上面的security配的)


多大

        1.8.JOL(即Java Object Layout)

        JOL(即Java Object Layout):OpenJDK提供的库,用于查看Java对象的内存布局,这个很有用,可以借助它来跟踪锁升级等过程。只需要引入Maven即可使用。

//引入依赖
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.16</version>
        </dependency>

//代码

class TTTT {
    public static void main(String[] args) {
        System.err.println(ClassLayout.parseInstance(new Person()).toPrintable());
        System.err.println(ClassLayout.parseClass(Person.class).toPrintable());
    }
}

class Person {
    private int age = 1;
    private String name = "zhangsan";
}

//代码执行结果
com.marchon.learning.Person object internals:
OFF  SZ               TYPE DESCRIPTION               VALUE
  0   8                    (object header: mark)     0x0000005e4c804101 (hash: 0x5e4c8041; age: 0)
  8   4                    (object header: class)    0xf8010dd9
 12   4                int Person.age                1
 16   4   java.lang.String Person.name               (object)
 20   4                    (object alignment gap)    
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

2.分析工具使用

2.1 jps和jinfo

常用命令: jps (输出java进程号pid)、 jps -l (输出java进程号和详细的jar信息)    、  jinfo pid(输出 java进程系统参数和jvm参数)、jinfo -flags pid (指输出jvm参数信息)

2.2 jstack

        jstack 是 JDK 自带的一种堆栈跟踪工具,可用于生成 JVM 当前时刻的线程快照。线程快照是当前 JVM 内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过 jstack 来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果 java 程序崩溃生成 core 文件,jstack 工具可以用来获得 core 文件的 java stack 和 native stack 的信息,从而可以知道 java 程序是如何崩溃和在程序何处发生问题。另外,jstack 工具还可以 attach 到正在运行的 java 程序中,看到当时运行的 java 程序的 java stack 和 native stack的信息, 如果现在运行的 java 程序呈现 hung 的状态,jstack 是非常有用的。

        简而言之,jstack 主要用来查看 Java 线程的调用堆栈,可以用来分析线程问题(如死锁、死循环、CPU 占用过高)。

  • -F:当正常输出的请求不被响应时,强制输出线程堆栈
  • -m:如果调用到本地方法的话,加上此参数可以显示本地方法的堆栈
  • -l:最常用的一个参数,除堆栈外,显示关于锁的附加信息,在发生死锁时可以用 jstack -l pid 来观察锁持有情况

把 jstack 的输出重定向到文件中,就可以分析了。

// 比如
jstack -l <pid> >> thread.log

java中锁的实现是通过monitor来实现的,它可以看成是对象或者 Class 的锁。每一个对象都有,也仅有一个 monitor。下图描述了线程和 Monitor 之间的关系,以及线程的状态转换图:

  • 进入区(Entry Set):表示线程通过 synchronized 要求获取对象的锁。如果对象未被锁住,则变为拥有者,否则在进入区等待。一旦对象锁被其他线程释放,立即参与竞争。
  • 拥有者(The Owner):表示某一线程成功竞争到对象锁。
  • 等待区(Wait Set):表示线程通过对象的 wait 方法,释放对象的锁,并在等待区等待被唤醒。

        从图中可以看出,一个 Monitor 在某个时刻,只能被一个线程拥有,该线程就是 Active Thread,而其它线程都是 Waiting Thread,分别在两个队列 Entry Set 和 Wait Set 里面等候。在 Entry Set 中等待的线程状态是 Waiting for monitor entry,而在 Wait Set 中等待的线程状态是 “in Object.wait()”。

使用 jstack 分析死锁步骤非常简单:
  1. jps 获取 pid
  2. jstack -l pid 打印堆栈信息
  3. 分析堆栈信息,一般来说 Java-level 的死锁,jstack 能自动检测出来。

比如下面这段 jstack 打印的堆栈信息,就是 jstack 自动检测出了一个 Java-level 死锁:

  • Thread-0 锁住了<0x00000007d6aa2c98>,尝试获取 <0x00000007d6aa2ca8> 的锁
  • Thread-1 锁住了<0x00000007d6aa2ca8>,尝试获取 <0x00000007d6aa2c98> 的锁
Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f0134003ae8 (object 0x00000007d6aa2c98, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f0134006168 (object 0x00000007d6aa2ca8, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
    at javaCommand.DeadLockclass.run(JStackDemo.java:40)
    - waiting to lock <0x00000007d6aa2c98> (a java.lang.Object)
    - locked <0x00000007d6aa2ca8> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:745)
"Thread-0":
    at javaCommand.DeadLockclass.run(JStackDemo.java:27)
    - waiting to lock <0x00000007d6aa2ca8> (a java.lang.Object)
    - locked <0x00000007d6aa2c98> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

        需要注意的是,jstack 只能自动检测 Java 线程间的死锁,不能检测到其它类型的线程状态,比如本地线程或者操作系统线程的状态。

如果要分析本地线程或者操作系统线程是否出现了死锁,可以在使用 jstack 时加上 -m 参数,把本地线程堆栈一起打印起来进行分析。

2.2.1 jstack分析锁信息和死锁

使用 jstack 查看线程堆栈信息时可能会看到的线程的几种状态

  • New:创建后尚未启动的线程处于这种状态,不会出现在Dump中。
  • RUNNABLE:包括Running和Ready。线程开启start()方法,会进入该状态,在虚拟机内执行的。
  • Waiting:无限的等待另一个线程的特定操作。
  • Timed Waiting:有时限的等待另一个线程的特定操作。
  • Blocked:在程序等待进入同步区域的时候,线程将进入这种状态,在等待监视器锁。
  • Terminated:已终止线程的线程状态,线程已经结束执行。

Dump 文件的线程状态一般其实就以下3种:

  • RUNNABLE,线程处于执行中
  • BLOCKED,线程被阻塞
  • WAITING,线程正在等待

 常见 dump 内容

  • locked <地址> 目标:申请对象锁成功,监视器的拥有者。
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at com.jiuqi.dna.core.internal.db.datasource.PooledConnection.prepareStatement
  • waiting to lock <地址> 目标:申请对象锁未成功,在 Entry Set 等待。
// 一个线程锁住某对象,大量其他线程在该对象上等待:
"blocker" runnable
java.lang.Thread.State: RUNNABLE
at com.jiuqi.hcl.javadump.Blocker$1.run(Blocker.java:23)
- locked <0x00000000eb8eff68> (a java.lang.Object)
"blockee-11" waiting for monitor entry
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.hcl.javadump.Blocker$2.run(Blocker.java:41)
- waiting to lock <0x00000000eb8eff68> (a java.lang.Object)
"blockee-86" waiting for monitor entry
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.hcl.javadump.Blocker$2.run(Blocker.java:41)
- waiting to lock <0x00000000eb8eff68> (a java.lang.Object)
  • waiting on <地址> 目标:释放对象锁,在等待区等待被唤醒。
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo
- locked <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run

2.2.2jstack分析cpu占用

        cpu飙高分析流程:稍后写个case复现一把。

1.top 查看占用 CPU 较高的进程,可以发现 pid 为 21340 的进程 CPU 占用较高。

2.top -Hp pid 可以查看该进程下各个线程的 CPU 使用情况,可以发现线程21350的 CPU 占用较高

3.jstack -l pid >> dump.log 将线程堆栈信息保存下来

4.分析堆栈信息,thread dump 中,每个线程对应一个十六进制的 nid(native thread id),将 21350 转成十六进制 5366 然后 grep 查看相关信息即可:查看线程信息附近线程状态,重点关注Blocked

2.3jstat

        jstat 是 JDK 自带的一个命令行工具,全称为 Java Virtual Machine statistics monitoring tool,可以用来监视和分析 Java 应用程序的内存使用和性能情况。jstat 命令可以显示有关 Java 堆和非堆内存使用情况、类加载、垃圾回收、线程和编译器等方面的信息。

jstat [ generalOption | outputOptions vmid [ interval[s|ms] [count] ] ]


参数说明:

generalOption:一般选项,用于设置 jstat 命令的全局行为。可以是以下选项之一:
-class:显示类加载情况。
-compiler:显示JIT编译器统计信息。
-gc:显示垃圾回收统计信息。
-gccapacity:显示垃圾回收堆内存使用情况。
-gcmetacapacity:显示垃圾回收非堆内存使用情况。
-gcnew:显示新生代垃圾回收统计信息。
-gcnewcapacity:显示新生代垃圾回收堆内存使用情况。
-gcold:显示老年代垃圾回收统计信息。
-gcoldcapacity:显示老年代垃圾回收堆内存使用情况。
-gcutil:显示垃圾回收堆内存使用情况总览。
-printcompilation:显示 JIT 编译器编译情况。
outputOptions:输出选项,用于设置 jstat 命令的输出格式。可以是以下选项之一:
-t:输出时间戳。
-h:输出帮助信息。
-J:输出完整的 JVM 内部信息。
vmid:Java 虚拟机进程 ID 或进程名。
interval:指定采样间隔时间,默认单位是毫秒。可以使用 s 或 ms 后缀指定单位,例如 10s 或 500ms。
count:指定采样次数,默认是无限次。

常用命令

jstat -class pid  显示加载class的数量,及所占空间等信息:

显示列名 具体描述
Loaded 装载的类的数量
Bytes 装载类所占用的字节数
Unloaded 卸载类的数量
Bytes 卸载类的字节数
Time 装载和卸载类所花费的时间

        

jstat -compiler pid  显示VM实时编译的数量等信息:

显示列名 具体描述
Compiled 编译任务执行数量
Failed 编译任务执行失败数量
Invalid 编译任务执行失效数量
Time 编译任务消耗时间
FailedType 最后一个编译失败任务的类型
FailedMethod

最后一个编译失败任务所在的类及方法

jstat -gc pid 可以显示gc的信息,查看gc的次数,及时间:

显示列名 具体描述
S0C 年轻代中第一个survivor(幸存区)的容量 (字节)
S1C 年轻代中第二个survivor(幸存区)的容量 (字节)
S0U 年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U 年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC 年轻代中 Eden(伊甸园)的容量 (字节)
EU 年轻代中 Eden(伊甸园)目前已使用空间 (字节)
OC 老年代的容量 (字节)
OU 老年代目前已使用空间 (字节)
PC Perm(持久代)的容量 (字节)
PU Perm(持久代)目前已使用空间 (字节)
YGC 从应用程序启动到采样时年轻代中 gc 次数
YGCT 从应用程序启动到采样时年轻代中 gc 所用时间(s)
FGC 从应用程序启动到采样时老年代(full gc) gc 次数
FGCT 从应用程序启动到采样时老年代(full gc) gc 所用时间(s)
GCT 从应用程序启动到采样时 gc 用的总时间(s)

jstat -gccapacity pid 显示 VM 内存中三代(young, old, perm)对象的使用和占用大小:

显示列名 具体描述
NGCMN 年轻代(young)中初始化(最小)的大小(字节)
NGCMX 年轻代(young)的最大容量 (字节)
NGC 年轻代(young)中当前的容量 (字节)
S0C 年轻代中第一个 survivor(幸存区)的容量 (字节)
S1C 年轻代中第二个 survivor(幸存区)的容量 (字节)
EC 年轻代中 Eden(伊甸园)的容量 (字节)
OGCMN 老年代中初始化(最小)的大小 (字节)
OGCMX 老年代的最大容量(字节)
OGC 老年代当前新生成的容量 (字节)
OC 老年代的容量 (字节)
PGCMN perm 代中初始化(最小)的大小 (字节)
PGCMX perm 代的最大容量 (字节)
PGC perm 代当前新生成的容量 (字节)
PC perm(持久代)的容量 (字节)
YGC 从应用程序启动到采样时年轻代中 gc 次数
FGC 从应用程序启动到采样时老年代(full gc) gc 次数

jstat -gcutil pid 统计 gc 信息:

显示列名 具体描述
S0 年轻代中第一个 survivor(幸存区)已使用的占当前容量百分比
S1 年轻代中第二个 survivor(幸存区)已使用的占当前容量百分比
E 年轻代中 Eden(伊甸园)已使用的占当前容量百分比
O 老年代已使用的占当前容量百分比
P perm 代已使用的占当前容量百分比
YGC 从应用程序启动到采样时年轻代中 gc 次数
YGCT 从应用程序启动到采样时年轻代中 gc 所用时间(s)
FGC 从应用程序启动到采样时老年代(full gc) gc 次数
FGCT 从应用程序启动到采样时老年代(full gc) gc 所用时间(s)
GCT 从应用程序启动到采样时 gc 用的总时间(s)

jstat -gccause  pid 1000 10   同gcutil 多了一个gc     (打印10次,每次间隔1000ms)

2.4jmap和jcmd

        jmap 是 JDK 自带的一个命令行工具,可以用于生成 Java Heap Dump 文件,以及查看 Java 进程中的内存使用情况。

jmap [option]  <pid>
jmap [option] <executable  (to connect to a core file)
jmap [option] [server_id@] (to connect to remote debug server)

option:命令选项,常用选项如下:

-heap:打印 Java 堆概要信息,包括使用的 GC 算法、堆配置参数和各代中堆内存使用情况;
-histo[:live]: 打印 Java 堆中对象直方图,通过该图可以获取每个 class 的对象数目,占用内存大小和类全名信息,带上 :live,则只统计活着的对象;
-permstat 打印永久代统计信息;
-finalizerinfo 打印等待回收的对象信息
-dump: 以 hprof 二进制格式将 Java 堆信息输出到文件内,该文件可以用 JProfiler、VisualVM 或 jhat 等工具查看;
dump-options 选项:

live 只输出活着的对象,不指定则输出堆中所有对象
format=b 指定输出格式为二进制
file= 指定文件名及文件存储位置,例如:jmap -dump:live,format=b,file=D:\heap.bin
-F 与-dump: 或 -histo 一起使用,当没有响应时,强制执行;注意:不支持live子选项
pid:进程id
  • 查看大对象:
jmap -histo <pid>|less
  • 查看对象数最多的对象,并按降序排序输出:
jmap -histo <pid>|grep 关键字|sort -k 2 -g -r|less
  • 查看占用内存最多的对象,并按降序排序输出:
jmap -histo <pid>|grep 关键字|sort -k 3 -g -r|less

查看大对象jmap -histo pid

jmap -histo:live pid  统计 heap 中所有生存的对象的情况, 这个命令会先触发 gc 再统计:

jmap -dump:live,format=b,file=a.log pid

执行这个命令,JVM 会将整个 heap 的信息 dump 到一个文件,heap 如果比较大的话会导致这个过程比较耗时,并且执行的过程中为了保证 dump 的信息是可靠的会暂停应用。

该命令通常用来分析内存泄漏 OOM,通常做法是:

  • 首先配置 JVM 启动参数,让 JVM 在遇到 OutOfMemoryError 时自动生成 Dump 文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path
  • 使用命令 Dump Heap 信息
jmap -dump:format=b,file=/path/heap.bin pid
  • 使用 MAT 分析工具,如 jhat 命令分析 hprof 文件

2.5jhat

        jhat 全称为 Java Virtual Machine Heap Analysis Tool,即虚拟机堆转储快照分析工具。jhat 用于分析 heapdump 文件,它会建立一个HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果。 jhat 一般与 jmap 搭配使用,用于分析 jmap 生成的堆转储快照。jhat 是一个命令行工具,使用起来比较简便,但功能也相对简陋。如果条件允许的话,建议使用 JProfiler 或者 IBM HeapAnalyzer 等功能更强大的工具来分析 heapdump 文件。

jhat [options] heap-dump-file


option 具体选项及作用如下:

-J< flag >:因为 jhat 命令实际上会启动一个 JVM 来执行,通过 -J 可以在启动 JVM 时传入一些启动参数。例如,-J-Xmx512m 指定运行 jhat 的 JVM 使用的最大堆内存为 512 MB。 如果需要使用多个 JVM 启动参数,则传入多个 -Jxxxxxx。
-stack false|true:关闭跟踪对象分配调用堆栈。如果分配位置信息在堆转储中不可用,则必须将此标志设置为 false。默认值为 true。
-refs false|true:关闭对象引用跟踪。默认情况下,返回的指针是指向其他特定对象的对象,如反向链接或输入引用(referrers or incoming references),,会统计/计算堆中的所有对象。
-port port-number:设置 jhat HTTP server 的端口号,默认值 7000。
-exclude exclude-file:指定对象查询时需要排除的数据成员列表文件。 例如,如果文件列出了 java.lang.String.value,那么当从某个特定对象 Object o 计算可达的对象列表时,引用路径涉及 java.lang.String.value 的都会被排除。
-baseline exclude-file:指定一个基准堆转储(baseline heap dump)。 在两个 heap dump 文件中有相同 object ID 的对象会被标记为不是新的(marked as not being new),其他对象被标记为新的(new)。在比较两个不同的堆转储时很有用。
-debug int:设置 debug 级别,0 表示不输出调试信息。 值越大则表示输出更详细的 debug 信息。
-version:启动后只显示版本信息就退出。
2.6 jvisualvm

        最后说jvisualvm,因为jvisualvm是对前面jps、jinfo、jstack、jstat、jmap、jhat的汇总,集上面之大成,并提供了可视化的界面;还可以监控远程Java服务;支持监控JMX。安装完插件比JConsole的功能还要完善。JVisualVM比JConsole更强大:支持对CPU、内存运行进行采样、配置。推荐用JVisualVM。

jconsole都不能保存连接信息,每次都要输入

安装插件

插件下载地址:VisualVM: Plugins Centers

也可以单个插件下载,离线安装

安装成功后的效果

JAVA Dump:
JAVA Dump就是虚拟机运行时的快照,将虚拟机运行时的状态和信息保存到文件中,包括:

线程dump:包含所有线程的运行状态,纯文本格式

堆dump:包含所有堆对象的状态,二进制格式

上一篇:3、flex弹性盒布局(flex:1?、水平垂直居中、三栏布局)


下一篇:---初始Linux---