JVM监控及分析(01)

摘要:
2) JVM内存图① 新对象首先分配给伊甸园校园。当Eden园区已满时,jvm将触发YGC执行垃圾收集:A.根搜索以确定哪些对象具有引用,哪些对象需要GC识别。B、 将伊甸园校园中的活动对象移动到s0生存区,并将伊甸园园区中需要GC的对象移出。② 在垃圾收集过程中,整个Java应用程序的线程被挂起,在收到垃圾收集之前不会工作。YGC更加频繁。

一、引入

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

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

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

JVM监控及分析(01)第1张

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

JVM监控及分析(01)第2张

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

JVM监控及分析(01)第3张

配置压测并发及时间:

JVM监控及分析(01)第4张

查看聚合报告:

JVM监控及分析(01)第5张

 页面报堆内存溢出错误:

JVM监控及分析(01)第6张

查看日志:

JVM监控及分析(01)第7张

常见的内存溢出:

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

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

JVM监控及分析(01)第8张

如上图表明内存溢出

二、JVM说明

1、JVM内存管理

1)堆与栈:

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

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

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

2)JVM内存图解

JVM监控及分析(01)第9张

①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"

JVM监控及分析(01)第10张

重启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的末尾加上主机名

JVM监控及分析(01)第11张

重启tomcat

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

JVM监控及分析(01)第12张

点击连接

JVM监控及分析(01)第13张

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

2)jmap

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

JVM监控及分析(01)第8张

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

JVM监控及分析(01)第15张

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

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

vi init1.jsp

JVM监控及分析(01)第16张

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

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

JVM监控及分析(01)第17张

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

JVM监控及分析(01)第18张

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

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

JVM监控及分析(01)第19张

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

JVM监控及分析(01)第20张

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

JVM监控及分析(01)第21张

在此处由于虚拟机配置的原因,花费较长时间,需要说明的是,在对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

JVM监控及分析(01)第22张

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配置进行优化)

JVM监控及分析(01)第23张

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

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

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

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

JVM监控及分析(01)第24张

免责声明:文章转载自《JVM监控及分析(01)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇转:ORACLE的JDBC连接方式:OCI和THINNotepad++ 中如何将代码格式化下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Qt --- 信号槽:第五个参数

connect第五个参数说明: 1、Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。 2、Qt::DirectConnection:槽函数会在...

学习Android camera笔记 & 调用流程

参考:http://blog.csdn.net/xingyu19871124/article/details/7750189http://blog.csdn.net/BonderWu/article/details/5814278http://blog.chinaunix.net/uid-2630593-id-3307176.htmlhttp://zhid...

JVM 内存布局及 GC 原理

“java 的内存布局以及 GC 原理”是 java 开发人员绕不开的话题,也是面试中常见的高频问题之一。 java 发展历史上出现过很多垃圾回收器,各有各的适应场景,很多网上的旧文章已经跟不上最新的变化。本文详细介绍了 java 的内存布局以及各种垃圾回收器的原理(包括最新的 ZGC),希望阅读完后,大家对这方面的知识不再陌生,有所收获,同时也欢迎大家留...

Windows I/O完成端口

内容: 1、基本概念2、WINDOWS完成端口的特点3、完成端口(Completion Ports )相关数据结构和创建4、完成端口线程的工作原理5、Windows完成端口的实例代码 WINDOWS完成端口编程 摘要:开发网络程序从来都不是一件容易的事情,尽管只需要遵守很少的一些规则:创建socket,发起连接,接受连接,发送和接收数据,等等。真正的困难在...

Java多线程之控制执行顺序

 概念: 多线程在并发环境中的正常执行顺序是随机无序的,并不能按照期盼的结果输出。                因为启动一个线程时,线程并不会立即执行,而是等待CPU的资源调度,CPU能调度哪个线程,是通过多种复杂的算法计算而来。 (一)Thread的join()方法来解决这个问题        一般在多线程编程时,需要控制线程的先后执行顺序,比如:主线...

java单元测试之如何实现异步接口的测试案例

测试是软件发布的重要环节,单元测试在实际开发中是一种常用的测试方法,java单元测试主要用junit,最新是junit5,本人开发一般用junit4。因为单元测试能够在软件模块组合之前尽快发现问题,所以实际开发中投入产出比很高。实际使用难免会遇到异步操作的接口测试,最常用的情景是别人家的SDK封装了异步处理,需要用测试用例来验证SDK的流程,顺便测试参数的...