JVM优化概述
略!
JVM参数----待完善
JVM参数类型
-
标准参数
如:
-help, -version
,这种直接使用中划线带上的参数,就是标准参数。java -help
命令可以查看所有的标准参数 -
-X参数
称为
非标准参数
,意味着后续的JDK版本中可能会变化,而且变化了,Oracle官方也可能不会给任何的通知。java -X
命令可以查看所有的-X参数常用的几个-X参数,如下:
-Xint interpreted JVM运行,使用解释模式 -Xcomp compile JVM运行,使用编译模式 -Xmixed JVM运行,使用混合模式,JVM的默认运行模式,也是推荐使用的模式
JVM运行模式
-
-XX参数
使用率高,主要用于JVM参数调优,以及debug操作。
查看正在运行的JVM参数:jinfo
命令
命令格式:jinfo -falgs <进程id>
# 查询tomcat运行的进程id
# 方式1
ps -ef | grep tomcat
# 方式2
jps -l # JVM提供的查询进程信息的指令
# 查询进程信息
jinfo -flags 9552 # 9552是某个运行中的tomcat的进程id。 可能会有多个tomcat进程在运行。
查看JVM进程信息,还可以使用如下的命令:
java -XX:+PrintFlagsFinal -version
JVM内存模型
JDK1.7与JDK1.8,JVM内存模型存在较大的差异。
JDK1.7中的JVM内存模型
-
Young 年轻代
-
Eden
-
S0 通常称为
from survivor
-
S1 通常称为
to survivor
S0区与S1区是大小相同的。
-
-
Tenured 年老代
缓存中的对象往往会被转移到此区域去。
-
Perm 永久代
此区域主要保存class,method, filed对象,这部分空间一般不会出现内存溢出,除非一次加载了很多的类。实际中可能出现的情况:
在涉及到热部署的应用服务器时,有时会遇到
java.lang.OutOfMemoryError:PermGen space
的错误,这很可能是因为每次重新部署时,原来的类文件没有被卸载掉,这样就会造成大量的class对象保存在了perm区中,引发内存溢出。解决方案:重启应用服务器。
通常也不会出现GC过程。
-
Virtual 虚拟区
JVM堆最大内存与初始内存的差值,就体现在Virtual区。
JDK1.8中的JVM内存模型
注意:
Metaspace区所占用的内存空间不是在虚拟机内部,而是在本地内存空间中,这是JDK1.8与JDK1.7的JVM内存模型最大的区别所在。(Perm Area --> Metaspace Area)
细化出来,如下:
jstat命令
命令格式:jstat <-命令选项> <vmid> [时间间隔/ms] [查询次数]
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
参数说明:
- vmid Virtual Machine Identifier JVM进程id
查看类加载情况
查看tomcat中的类加载情况,运行的tomcat就是一个JVM进程。
# 查看tomcat进程id
jps -l
# 查看类加载情况
jstat -class 9552 # 9552是其中一个tomcat进程的id号
查看编译情况
# 查看tomcat进程id
jps -l
# 查看进程中类的编译情况
jstat -compiler 9552 # 9552是其中一个tomcat进程的id号
查看垃圾回收情况
# 查看tomcat进程id
jps -l
# 查看进程中类的编译情况
jstat -gc 9552 # 9552是其中一个tomcat进程的id号
jmap命令
可以查看更详细的信息
命令格式:
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)
查看heap区使用情况
# 查看tomcat进程id
jps -l
# 查看进程中类的编译情况
jmap -heap 9552 # 9552是其中一个tomcat进程的id号
查看JVM内存中的对象数量与大小
- jmap -histo <pid> 查看所有对象
- jmap -histo:live <pid> 查看活跃对象(或者说是存活对象)
# 查看tomcat进程id
jps -l
# 查看进程中类的编译情况
jmap -histo 9552 | more # 加个管道命令,分页查看。不然一次显示太多内容,看不过来。
将JVM内存使用情况,dump到磁盘文件中
# dump: 转存 -dump,是jmap命令的一个命令选项
jmap -dump:format=b,file=/test/dump.dat 9952
# 将进程id=9952的JVM内存使用情况,以二进制格式保存到`/test/dump.dat`文件中
某个进行的JVM内存使用情况,保存到磁盘文件后,就需要对其进行分析,以下介绍两种分析手段:
-
jhat
命令:命令格式:
jhat -port <端口号> <file>
file:文件的全路径名,如
/test/dump.dat
指定端口后,这个命令会将指定的
Heap Dump文件
进行解析,并在指定的端口上生成一个web应用,然后可以通过浏览器去访问,如:192.168.178.131:9999
。里面可以查看到上面指定的进程的JVM内存使用情况。OQL查询语言
: Object Query Language 浏览器访问上述解析结果的程序时,在其页面的最后,会有这个
对象查询语言
。 -
MAT工具
Memory Analyzer Tool,它是一款基于Eclipse的内存分析工具。这是一款可视化工具。
实战:模拟死锁,并使用jstack
命令查看程序
编写死锁的代码
以下代码可以模拟“死锁”。
使用命令行去运行以下的代码,出现死锁后,程序将没有任何反应。
public class DeadLockTest {
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public static void main(String[] args) {
new Thread(new Thread1()).start();
new Thread(new Thread2()).start();
}
private static class Thread1 implements Runnable{
@Override
public void run() {
synchronized (obj1){
System.out.println("Thread1拿到了obj1对象的锁!");
try {
// 让Thread1停顿2s的目的,是让Thread2去拿到obj2的锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2){
System.out.println("Thread1拿到了obj2对象的锁!");
}
}
}
}
private static class Thread2 implements Runnable{
@Override
public void run() {
synchronized (obj2){
System.out.println("Thread2拿到了obj2对象的锁!");
try {
// 让Thread2停顿2s的目的,是让Thread1去拿到obj1的锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1){
System.out.println("Thread2拿到了obj1对象的锁!");
}
}
}
}
}
运行代码
将代码放到Linux中运行。
-
在根目录
/
下新建一个test
目录,并创建一个java类文件DeadLockTest
-
使用EditPlus,编辑.java文件
-
将上述代码复制到其中
-
修改文件的编码为
UTF-8
- 文档 --> 文本编码 --> 转换文本编码,选择UTF-8
不修改编码,没法运行。
-
-
进入到
/test
目录中,执行以下java命令,运行程序
javac DeadLockTest.java # 编译
java DeadLockTest # 运行
一运行程序,程序就会进入死锁状态,表现出来的情况就是程序没任何反映了。
使用jstack
命令查看程序运行情况
jstack
命令的格式:jstack <vmid>
-
克隆一个命令窗口
-
使用jstack命令查看
# 查看当前运行的进程情况 jps -l # 查看 jstack 10955 # 10995是DeadLockTest程序所使用的端口
总结
这样,如果程序出现了没有任何反应的情况,就能够通过jstack
命令查看到到底发生了什么!
Java VisualVM工具
它是JDK自带的
一款功能强大的可视化JVM内存分析工具
!
它可以监控本地进行的JVM内存,也可以监控远程JVM进程(这是非常非常有用的,因为实际中,应用都是部署在远程服务器上的)。
- 以管理员身份直接运行exe文件即可打开此工具!
监控本地JVM
进入"本地"–> "VisualVM"中即可 查看。
监控远程JVM
这个需要远程主机进行配置,并在本地通过Java VisualVM去连接远程主机。
这项功能,需要借助于一款工具:JMT
JMT工具
JMT(Java Management Extensions, Java管理扩展工具),它是一个为应用程序、设备、系统等植入管理功能的框架。JMT可以跨越异构的操作系统(如本地主机是windows系统,远程主机是Linux系统,它也可以进行远程连接)、系统体系结构和网络传输协议,灵活地开发无缝集成的系统、网络与服务管理应用。
远程主机配置
以监控远程的Tomcat程序为例!
需要在tomcat的bin目录下,修改JVM配置文件catalina.sh
,在其中添加如下的配置内容:
JAVA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"
参数说明:
-Dcom.sun.management.jmxremote 允许使用JMX远程管理
-Dcom.sun.management.jmxremote.port=9999 JMX远程连接的端口设置
-Dcom.sun.management.jmxremote.authenticate=false 不进行身份认证(即任何用户都可以连接)
实际应用中,是需要开户身份认证的,这里只是方便测试。
-Dcom.sun.management.jmxremote.ssl=false 不使用ssl安全协议进行传输信息加密
修改配置文件后,重启Tomcat。
# 使用tail命令来查看tomcat启动日志
# 进入到tomcat的bin目录下
./startup.sh && tail -f ../logs/catalina.out
本地连接远程主机
在Java VisualVM中进行配置如下:
在这个地方,可能有的人能够连接上,有的人连接不上。
我就连接不上,具体原因还在研究之中。。。。。。
QQQQ: 出现问题了
- JMX远程连接不上