美文网首页
《深入理解Java虚拟机》读书笔记2

《深入理解Java虚拟机》读书笔记2

作者: 南宫萧言 | 来源:发表于2019-11-18 08:32 被阅读0次

    一、JDK命令行工具

    JDK命令行工具位于JDK的bin目录下,能在处理应用程序性能问题、定位故障时发挥很大的作用。

    这些工具都比较小,因为这些命令行工具大多数是jdk\lib\tools.jar类库的一层简单包装而已。

     注:tools.jar中的类库不属于Java的标准API;

    如果需要监控运行于JDK

    1.5的虚拟机之上的程序,在程序启动时要添加参数“-Dcom.sun.management.jmxremote”开启JMX管理功能,如果被监控程序运行于JDK1.6的虚拟机之上,那JMX管理默认是开启的,不需要在虚拟机启动时添加任何参数。

    下图列举了JDK主要命令行监控工具及用途:

    图1

    1、jps:虚拟机进程状况工具

    功能:可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class, main()函数所在的类)的名称,以及这些进程的本地虚拟机的唯一ID(LVMID, Local Virtual Machine Identifier)。

    注:对于本地虚拟器进程来说,LVMID与操作系统的进程ID(PID, Process Identifier)是一致的。

     jps命令格式:

    jps [options] [hostid]

       -q  :只输出LVMID, 省略主类的名称

       -m : 输出虚拟机进程启动时传递给主类main()函数的参数

       -l  :输出主类的全名,如果进程执行的是Jar包,输出Jar路径

       -v  : 输出虚拟机进程启动时JVM参数

    CMD进入Java的安装目录下的bin目录,输入:jps -l,会输出LVMID 和主类的全名。

    2、jstat:虚拟机统计信息监视工具

    jstat(JVM Statistics Monitoring Tool)是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,在只有控制台环境时,它将是运行期定位虚拟机性能问题的首选工具。

    jstat命令格式:

          jstat [    option vmid [interval [s | ms]    [count]]    ]

    注:其中VMID:如果是本地虚拟机进程,VMID与LVMID是一致的,如果是远程虚拟机进程,那么VMID的格式应当是:

          [protocol:] [//] lvid [@hostname[:port] /servername]

          参数interval和count代表查询间隔和次数。如果省略这两个参数,说明只查询一次,假设需要每250毫秒查询一次进程2764垃圾收集的状况,一共查询20次,那命令应当是:

          jstat  -gc 2764 250 20

    option选项:该选项代表用户希望查询的虚拟机信息,主要分为3类:类装载、垃圾收集和运行期编译状态。具体选项及作用如下:

    图2

    3、jinfo :Java 配置信息工具

    jinfo(Configuration Info for Java)的作用是实时地查看和调整虚拟机的各项参数。

    注:JDK1.6中,jinfo对于Windows平台的功能仍然有较大的限制,只提供了最基本的 -flag选项。

        jinfo命令格式:jinfo [ option ] pid

    例如:查询CMSInitiatingOccupancyFraction参数值:jinfo -flag CMSInitiatingOccupancyFraction 8088

    4、jmap : Java内存映像工具

    jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件)。

          如果不使用jmap命令,可以通过指定虚拟机参数来获得dump文件,例如:指定-XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机在OOM异常出现之后自动生成dump文件,通过-XX:+HeapDumpOnCtrlBreak参数则可以使用【Ctrl】+ 【Break】键让虚拟机生成dump文件。或者Linux下通过Kill -3命令。

          jmap的作用并不仅仅是为了获取dump文件,它还可以查询finalize执行队列,Java堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。

          与jinfo命令一样,jmap在windows平台下有些功能是受限的,可以使用的是-dump选项来获取dump文件、-histo选项用来查看每个类的实例、空间占用统计等。

    jmap命令格式:

          jmap [ option ]  vmid

    option选项:

    图3

    5、jhat:虚拟机堆转储快照分析工具(dump分析工具)

    通过jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,来分析jmap生成的堆转储快照。jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,可以在浏览器中查看。

        jhat工具很少使用,因为有比它强大的专业分析dump的工具,比如VisualVM、Eclipse Memory Analyzer、IBM HeapAnalyzer等工具。

    6、jstack : Java 堆栈跟踪工具

    jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump或javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因。

        jstack命令格式:

        jstack [ option ] vmid

    图4

    二、JDK可视化工具

    1、JConsole :Java监视与管理控制台

    JConsole(Java Monitoring and Management Console)是一款基于JMX的可视化监视和管理的工具。

    2、VisualVM:多合一故障处理工具

    VisualVM(All-in-One Java Troubleshooting Tool)是目前随JDK发布的功能最强大的运行监控和故障处理程序。

          它的一个重要优点是:不需要被监视的程序基于特殊Agent运行,因此它对应用程序的实际性能的影响很小,使得它可以直接应用在生产环境中 。

          它需要装扩展插件才能发挥它的功能,插件都以.nbm为后缀的包,安装插件:点击“工具”-> "插件"-> "已下载"菜单。

    以下是插件的介绍:

    ** BTrace:动态日志跟踪

              它的作用是在不停止目标程序运行的前提下,通过HotSpot虚拟机的HotSwap技术动态加入原本并不存在的调试代码,这可以在不停止部署的程序的条件下调试问题。

    BTrace的用法还有很多,打印调用堆栈、参数、返回值只是最基本的应用,在它的网站上有使用BTrace进行性能监视、定位连接泄漏、内存泄漏、解决多线程竞争问题等的使用例子。

    三、故障处理

    1、案例一:高性能硬件上的程序部署策略

    在高性能硬件上部署程序,目前主要有两种方式:

          ** 通过64位JDK来使用大内存

          ** 使用若干个32位虚拟机建立逻辑集群来利用硬件资源

    通过第一种方式,即64位JDK来管理大内存,需要考虑下面可能的问题:

          ** 内存回收导致的长时间停顿;(一次Full GC会花费较长时间)

          ** 现阶段,64位JDK的性能测试结果普遍低于32位JDK

          ** 需要保证程序足够稳定,因为这种应用要是产生堆溢出几乎就无法产生堆转储快照(十几GB的dump文件),即使产生了也无法分析;

          ** 相同的程序在64位JDK中消耗的内存一般比32位JDK大,这是由于指针膨胀及数据类型对其补白等因素导致的。

    通过第二种方式,具体做法是在一台物理机器上启动多个应用服务器进程,给每个服务器进程分配不同的端口,然后在前端搭建一个负载均衡器,以反向代理的方式来分配访问请求。这种方式需要考虑的问题是:

          ** 尽量避免节点竞争全局的资源,最典型的就是磁盘竞争

          ** 很难最高效率地利用某些资源池,譬如连接池

          ** 各个节点仍然不可避免地受到32位的内存限制

          ** 大量使用本地缓存的应用,在逻辑集群中会造成较大的内存浪费,因为每个逻辑节点上都有一份缓存,可以考虑把本地缓存改为集中式缓存。

    2、集群间同步导致的内存溢出

    3、堆外内存导致的溢出错误

          关于Direct Memory的垃圾回收:垃圾收集进行时,虚拟机会对Dircet Memory进行回收,但是它不会在发现Dircet Memory空间不足时就通知收集器进行垃圾回收,它只能等待老年代满了后Full GC,然后“顺便地”帮它清理掉内存的废弃对象。或者等到抛出内存溢出异常时,先chatch掉,再在catch块里面进行System.gc()。如果此时虚拟机打开了-XX:+DisableExplicitGC开关,那么仍然是不能清理Dircet Memory空间的。

          从实践角度出发,除了Java堆和永久代之外,我们要注意以下区域也可能占用较多的内存:这里所有的内存总和会受到操作系统进程最大内存的限制:

          ** 、Direct Memory: 可通过-XX:MaxDirectMemorySize调整大小,内存不足时抛出OutOfMemoryError或OutOfMemoryError:Direct buffer memory。

          **、线程堆栈:可通过-Xss调整大小,内存不足时抛出StackOverflowError(纵向无法分配,即无法分配新的栈帧)或OutOfMemoryError:unable to create new native thread(横向无法分配,即无法建立新的线程)。

          **、Socket缓存区:每个Socket连接都Receive和Send两个缓存区,分别占大约37KB和25KB的内存,连续多的话这块内存占用也比较可观。如果无法分配,则可能会抛出IOException:Too many open files异常。

          **、JNI代码:如果代码中使用JNI调用本地库,那本地库使用的内存也不在堆中。

          **、虚拟机和GC:虚拟机和GC的代码执行也要消耗一定的内存。

    4、外部命令导致系统缓慢

          每个用户请求的处理都需要执行一个外部shell脚本来获取系统的一些信息。执行这个shell脚本是通过Java的Runtime.getRuntime().exec()方法来调用的,这种调用方式可以达到目的,但是它在Java虚拟机中非常消耗资源,即使外部命令本身能很快执行完毕,频繁调用时创建进程的开销也非常可观。

          原因:Java虚拟机执行这个命令的过程是:首先克隆一个和当前虚拟机拥有一样环境变量的进程,再用这个新的进程去执行外部命令,最后再退出这个进程。频繁执行此过程,系统消耗会很大,不仅是CPU,内存的负担也很重。

          解决方法:去掉shell脚本执行的语句,改为使用Java的API去获取系统信息。

    5、服务器JVM进程崩溃

    ---------------------

    作者:demystify

    来源:CSDN

    原文:https://blog.csdn.net/xiaoxiaoyusheng2012/article/details/52958021

    版权声明:本文为博主原创文章,转载请附上博文链接!

    相关文章

      网友评论

          本文标题:《深入理解Java虚拟机》读书笔记2

          本文链接:https://www.haomeiwen.com/subject/pqekyqtx.html