zoukankan      html  css  js  c++  java
  • JVM监控及分析(01)

    一、引入

    进入tomcat下的webapps文件夹中,将test1.war上传至该目录下,重启tomcat:

    sh startup.sh && tail -f ../logs/catalina.out

    这时候tomcat会自动解压war包,文件夹文件如下:

    在浏览器中访问该项目jsp文件的地址:

    使用JMeter对该地址进行压测,录制http请求:

    配置压测并发及时间:

    查看聚合报告:

     页面报堆内存溢出错误:

    查看日志:

    常见的内存溢出:

    java.lang.OutOfMemoryError: PermGen space → 持久代内存溢出
    java.lang.OutOfMemoryError: Java heap space → 堆内存溢出
    java.lang.StackOverflowError → 栈内存溢出

    通过:jmap -heap pid可以查看内存状况:

    如上图表明内存溢出

    二、JVM说明

    1、JVM内存管理

    1)堆与栈:

    栈是运行时的单位,而堆是存储的单位。

    栈解决程序的运行问题,即程序如何执行,或者说如何处理数据
    堆解决的是数据存储的问题,即数据怎么放、放在哪儿
    栈的优势是存取速度比堆要快,仅次于寄存器,栈数据可以共享

    在Java中一个线程就会相应有一个线程栈与之对应,不同的线程执行逻辑有所不同,因此需要一个独立的线程栈
    堆是所有线程共享的。
    栈是运行的单位,存储的信息跟当前线程(或程序)相关的信息,包括局部变量、程序运行状态、方法返回值等等,优势是栈的优势是存取速度比堆要快,仅次于寄存器,栈数据可以共享。缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
    堆只负责存储对象信息,堆的优势是可以动态地分配内存大小,但缺点是,由于要在运行时动态分配内存,存取速度较慢。

    2)JVM内存图解

    ①new出来的对象,最开始优先分配进入伊甸园区,伊甸园区满了之后,jvm会触发YGC进行垃圾回收:

      A、寻根判断,哪些对象有引用,哪些对象需要进行GC标识

      B、将伊甸园区的存活对象移动到s0存活区,将伊甸园区的需要GC的对象GC掉

    ②在执行垃圾回收的过程中,整个Java应用程序的线程是暂停没有工作的,直至垃圾回收接收之后,YGC较为频繁。由此可知jvm在进行YGC的时候,会影响应用系统性能。

    ③当伊甸园区再次满了的时候:

      A、jvm会再次对伊甸园区的对象进行寻根判断标识,然后将存活的对象移动到s1存活区,将伊甸园区的不需要的对象GC掉;

      B、对s0区中的对象进行寻根判断,存活的移动到s1存活区,将s0中不需要的对象GC掉。

    上述A、B步骤就叫做两个存活区大小相等,位置互换。

    ④当伊甸园区第3次满了的时候:

      A、jvm会再次对伊甸园区的对象进行寻根判断标识,然后将存活的对象移动到s0存活区,将伊甸园去的不需要的对象GC掉;

      B、对s1区中的对象进行寻根判断,存活的移动到s0存活区,将s1中不需要的对象GC掉。大小相等,位置互换。

    ⑤jvm在进行YGC的时候重复上述①到④步骤。

    ⑥大对象直接进入老年代(大对象 → JDK默认设置大对象的大小)

    ⑦长期存活的对象进入老年代(长期存活的对象,默认age=15即进行了15次GC之后,有对象一直存活,那么在下次GC的时候,该对象会进入老年代)

    ⑧对象动态分配原则:比方说,在存活区里边存在着各年龄的对象,jvm会根据一定的方法判断,当某个年龄的对象之和超过存活区的一半大小,那么jvm会将大于等于该age的对象全部移动到老年代

    ⑨随着时间的推移,老年代内存空间满了之后会jvm会触发FullGC,FullGC的时候会回收整个堆内存和非堆内存(回收的过程都会进程寻根判断,GC掉没用的对象,意味着各区GC完之后还会有些存活的对象);

    随着Java程序的继续运行还会触发FullGC,如果对象回收不彻底,老年代被占用的内存比例会越来越高,当再次要往老年代中放置对象的时候,不能将对象再放入老年代了,这时候jvm就会抛出内存溢出的异常。

    老年代占整个堆内存的3/8(官方建议)

    在进行jvm性能优化的核心要素:尽量延缓FullGC的间隔时间

    FullGC的触发条件:

      ①老年代满了的时候,会触发FullGC

      ②permgen(持久代)满了的时候,也会触发FullGC

      ③代码中显示调用System.gc();Runtime.getRuntime().gc();也会触发FullGC

      ④一些悲观策略RMI(基于tcp/ip通信)框架中,会定时的显示调用System.gc();,会触发FullGC

      ⑤Jmap-dump时,也会触发FullGC

    2、JVM内存监控

    1)jconsole.exe

    jconsole.exe连接服务器tomcat

    A、运行本地JDK,/bin目录下的jconsole.exe

    B、配置linux服务端的catalina.sh文件,在文件的前边加上配置:

    JAVA_OPTS="-Xms256m -Xmx256m -Xss1024K -XX:PermSize=128m -XX:MaxPermSize=128m -Djava.rmi.server.hostname=192.168.20.129 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"

    重启tomcat,在关闭tomcat服务时,报错:

    Using CATALINA_BASE: /usr/local/MyFiles/apache-tomcat-8.5.15
    Using CATALINA_HOME: /usr/local/MyFiles/apache-tomcat-8.5.15
    Using CATALINA_TMPDIR: /usr/local/MyFiles/apache-tomcat-8.5.15/temp
    Using JRE_HOME: /usr/local/MyFiles/jdk1.8.0_131
    Using CLASSPATH: /usr/local/MyFiles/apache-tomcat-8.5.15/bin/bootstrap.jar:/usr/local/MyFiles/apache-tomcat-8.5.15/bin/tomcat-juli.jar
    Java HotSpot(TM) Client VM warning: ignoring option PermSize=128m; support was removed in 8.0
    Java HotSpot(TM) Client VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
    错误: 代理抛出异常错误: java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostException: Linz: Linz: 未知的名称或服务

    tomcat无法关闭

    解决办法:

    vi /etc/hosts ,在文件127.0.0.1的末尾加上主机名

    重启tomcat

    C、使用windows端JDK,bin目录中的jconsole.exe连接服务端:

    点击连接

    至此使用window端的jconsole.exe连接服务器的tomcat成功

    2)jmap

    A、jmap -heap pid → 发现是否内存泄漏

    B、jmap -histo pid > test.txt → 打印堆内存的快照信息,找内存溢出的原因

    可以确定,上图中的cn.test.TestBean是自己写的代码

    进入项目目录cd ../webapps/test1,查看代码:

    vi init1.jsp

    泄漏是过程,溢出是结果,由此可知TestMain.list.add(b);是造成内存溢出的原因

    C、jmap -dump:live,format=b,file=lhy0523.bin pid

    这时候在/usr/local/MyFiles/apache-tomcat-8.5.15/webapps/test1文件夹中生成了一个lhy0523.bin文件

    注意:在用jmap命令dump的时候,需要关闭浏览器访问的http://192.168.20.129:8080/test1/init1.jsp网页,要不dump不下来

    D、使用jhat -J-mx512m lhy0523.bin命令对lhy0523.bin文件进行解析:

    上图报错,说明内存不过,需要将命令的内存改大些:jhat -J-mx900m lhy0523.bin,如下图:

    这时候,就可以在客户端浏览器中,用IP加端口号7000,访问:

    在此处由于虚拟机配置的原因,花费较长时间,需要说明的是,在对test1进行压测的时候,要时刻跟踪日志,看到日志报内存溢出,要及时停止压测,以避免C步骤中通过jmap -dump:live,format=b,file=filename.bin pid 命令生成的bin文件过大,而导致在该步骤D中使用jhat -J-mx900m filename.bin这个命令由于内存不够,而导致内存溢出。

    3)jstack

    作用:将dump线程栈信息(方法调用)

    用法:jstack 1773 > test.txt

    jstack → 分析线程栈(cpu高、IO高、负载高)执行调用方法、获取资源

     线程栈的状态分析:

       ①查看线程的状态,看有没有block状态,at后边是在执行什么调用的是什么方法

       ②应用程序代码响应时间比较长,cpu、负载不高→分析线程栈中的waiting状态,查看线程在等待什么,等待的资源,就是造成系统性能瓶颈的原因

       ③cpu高→running,查看在获取什么资源信息

       定位uscpu高的原因:查看消耗查看cpu高的进程,再看该进程下的线程,再看占用cpu高的线程执行的方法,这个执行的方法就是造成cpu高的原因

         A、top -H -p pid → 查看进程下的线程,分析哪个线程占用cpu高(消耗cpu高的线程,看TIME+,谁占用时间高,就是消耗cpu最高的线程)

         B、使用jstack命令,查看线程栈,并且重定向到一个文件中,将A中,线程的id,转化为16进制的,在重定向中的文件查找,从而找到方法

      另外一种查看进程下,线程的方法:ps -mp pid -o THREAD,tid,time → 替换掉pid

      linux下,将十进制转化为十六进制:printf "%x " tid → tid为线程id

    4)jstat

    作用:监听垃圾回收,内存使用的情况

    jstat -gcutil pid 3000 20 → 监控垃圾回收情况(YGC的时间、次数、FullGC的频率从而对代码、jvm配置进行优化)

    命令监视对应用程序造成的性能影响最小

    任何监控工具都会耗费系统性能,所以在进行监控的时候,最好使用命令行工具,对性能干扰最小

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

    想为你去蹦极,诉说心中对你的眷念... ...

    如欢如殇 授以青春鲜活肢体奔忙 如思如忘 驱以老朽深沉灵魂冥想 始自情热激荡 从未敢终于世事炎凉 无能执手相望 无法去尝试结发同床 无力至心死身僵 一息坚强 ------ 我一直没有放弃,如果你也能看到 修身 修禅
  • 相关阅读:
    clipboard复制剪贴板功能,以及用sea.js时报错---Uncaught ReferenceError: Clipboard is not defined
    关于字体跨域
    关于 sass
    移动端返回上一页
    第二次结对编程作业
    第一次结对编程作业
    第一次个人编程作业
    软工实践第一次作业
    XGB算法梳理
    GBDT算法梳理
  • 原文地址:https://www.cnblogs.com/lz2lhy/p/6886829.html
Copyright © 2011-2022 走看看