JVM优化-JDK1.8--常用内存分析指令和工具

1、JVM的运行参数

jvm有很多运行参数,绝大多数保持默认即可

1.1:三种参数类型

标准参数
以-加小写字母,这种参数是稳定的,基本不会发生变化
-help
-version
-X参数(非标准参数)
这种参数是不稳定的,在未来的版本中可能会发生改变
-Xint
-Xcomp
-XX参数 (使用频率比较高的非标准参数)
这种参数往往用于jvm调优或者debug,使用频率比较高
-XX:newSize
-XX:+UseSerialGC

标准参数:
可以使用 java -help 查看所有标准参数

-D设置系统参数

-Dstr=123
即可给JVM添加系统参数str,其值为123

1.2: -server -client参数

可以设置server模式或者client模式
可以通过-server 或者-client设置系统参数
使用-server参数,默认堆空间会大一点,默认启动的是并行垃圾回收器,特点是启动时间比较长,运行速度快

-client模式 VM分配堆空间会保守一些,堆空间相对较小,默认使用串行垃圾回收器,它的特点是启动快,运行慢,适用于开发调试等。运行速度会比较慢一些

系统根据当前系统硬件配置情况,自动选择server或者client,
1:如果使用的是32位windows,则无论硬件如何配置,都自动启用client模式
2:如果是其他操作系统,如果内存大于2G且双核及以上,则默认启动server模式,否则使用client模式
3:在64位系统中,则没有client模式,只有server模式

1.3:-X参数

X参数是java的非标准参数
可以使用 java -X 来查看所有的-X命令,
非标准参数,有可能会在后续版本中发生变更

-Xint -Xcomp -Xmixed参数
这三个是比较常用的参数
这三个参数是指的JVM的运行模式
-Xint是解释模式:强制要求jvm执行所有字节码,这样效率比较低(通常低10倍或更多)
-Xcomp 正好相反,是第一次执行的时候把所有字节码都编译成本地代码,从而带来更大程度的优化
使用这个参数,是牺牲了部分JIT编译器
-Xmixed:混合模式 (JVM默认就是混合模式)

1.4: -XX参数

是非标准参数,主要用于JVM调优和debug操作
-XX参数分为两种,一种是布尔类型,一种是非布尔类型

1:boolean类型:
使用格式为:
-XX:[±] 其中+或者-表示启用或者禁用,name为参数名称或者属性
例如: -XX:+DisableExplicitGC 表示启用禁用手动调用GC
2:非布尔类型
-XX:=
表示给某个参数设置某个值
例如: -XX:NewRetio=1 表示新生代和老年代的比值

1.5:-Xms 和-Xmx参数

它们属于-XX参数
它们设置堆内存的初始大小和最大大小

-Xmx 等价于
-XX:MaxHeapSize
-Xms 等价于
-XX:InitialHeapSize

例如:-Xmx2048m
-Xms512m

可以根据服务器的配置适当的调整jvm的堆内存的大小,让程序跑的更快

1.6:查看jvm运行参数

有时候我们可能需要查看jvm的运行参数
可能存在两种情况:
1:运行java命令的时候打印运行参数;
2:查看当前正在运行的jvm的运行参数

运行java命令的时候打印运行参数,可以在java命令后加上 -XX:+PrintFlagsFinal参数
例如: java -XX:+PrintFlagsFinal Test (Test是编译好的class文件)

则可以打印出一片当前运行时的参数,其中用=表示的则是默认值,用:=表示的,则是说明这个参数运行时被修改过。

查看正在运行的jvm的参数
需要借助于jinfo命令查看
可以先运行一个tomcat,
然后 查看当前tomcat的进程号
查看进程号的方法有:
使用grep查看: ps aux|grep tomcat
使用jps命令: jps (直接查看当前运行的java程序的进程)
使用 jps -l 可以查看当前运行的java程序的进程,并附带详细路径。

现在使用jinfo命令
jinfo -flags 3037 (假如当前运行jvm的进程号是3037)
可以查看到当前运行的jvm的所有运行参数

也可以指定查看某一个参数的值:
jinfo -flag InitialHeapSize 3037 (查看初始化堆内存大小)

2、JVM内存模型

2.1:JDK1.7的堆内存模型

在这里插入图片描述
堆内存模型被分为三个区域:年轻代、老年代、永久区
年轻代:Yong
yong被分为三个部分:eden区、两个严格大小相等的survivor区
其中survivor区一定是严格大小相等的,同一时刻只有一个是启用的,另一个留着垃圾回收的时候复制数据使用。
new对象的时候,首先放到eden区,当eden区变满的时候,开始垃圾回收,垃圾被回收掉,依然存活的对象转移到survivor区。
如果经过几次垃圾回收后,survivor区的对象依然存活,那么将会向老年代区Tenured移动,用来保证年轻代区域有足够的空间可用
老年代:Tenured
老年代保存生存周期比较长的对象,并不一定是永久性的存活,也可能会被回收, 一般系统中如果使用了application级别的缓存,则缓存中的对象一般会被转移到该区域
永久区:Perm
永久区一般保存class类名、method方法、field对象属性
永久区一般不会出现溢出,除非是一次性加载过多的类。

在热部署的时候,可能会存在每次热部署都将类加入Perm,并不会被卸载,时间长了,就会出现内存溢出,这种情况,重启即可。

2.2:JDK1.8的堆内存模型

在这里插入图片描述
JDK1.8的堆内存模型中,没有了永久代,取代它的是元数据空间
年轻代和老年代依然如常
年轻代由:Eden + Survivor*2
老年代由:Old Gen
元数据空间(Metaspace)不占用虚拟机JVM内部空间,直接使用物理内存空间

在这里插入图片描述
其中CodeCache区域,即存放类class部分
CCS是存储类的压缩指针,如果开启压缩指针,则使用该内存,否则,不使用。

注意:并不是所有的new的对象都会进入年轻代,一般情况,new的对象比较小的话,是进入年轻代Eden,如果new出来的对象非常大的话,直接就会进入老年代。

2.3:为什么要废弃1.7中的永久代

官方给出的解释是为了和JRockit进行融合,
JRockit也是一个非常优秀的JVM,它没有永久代的设置
现实情况是,在使用过程中,由于永久区的设置经常不够用,会出现OutOfMemerryError;
废弃永久代后,只需要关注年轻代和老年代的内存即可。

2.4: 通过jstat命令查看堆内存使用情况

jstat [-命令选项] [vmid][间隔时间/毫秒][查询次数]

vimd:进程id

查看类加载情况
jstat -class 3037
在这里插入图片描述
得到统计结果:
Loaded:加载的class的数量
Bytes:所占空间的大小
Unloaded:未加载数量
Bytes:未加载占用空间
Time:所用时间

查看编译情况
jstat -compiler 3037
在这里插入图片描述
Compiled:编译的数量
Failed:失败数量
Invalid:不可用数量
Time:编译时间
FailedType:失败类型
FailedMethod:失败的方法

垃圾回收统计
jstat -gc 3037
在这里插入图片描述
S0C:第一个survivor区的大小(KB)
S1C:第二个survivor区的大小(KB)
S0U:第一个survivor区的使用大小(KB)
S1U:第二个survivor区的使用大小(KB)
EC:Eden区的大小
EU:Eden区的使用大小
OC:Old区的大小
OU:Old区的使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗时间

刚才的使用是打印了一次,如果需要打印多次,则可以增加时间间隔和设置打印次数(比如一秒钟打印一次,总共打印10次)
jstat -gc 3037 1000 10
则会每隔1秒钟打印一次,总共打印10次。

3、jmap的使用及内存溢出分析

使用jps命令查看正在运行的jvm进程
在这里插入图片描述

3.1:查看内存使用情况

jmap -heap 15304
在这里插入图片描述图中可以看到
① heap configuration 堆配置信息
②heap usage 堆使用情况

3.2:查看堆内存对象的数量和大小

jmap -histo 15304 | more
查看堆内存中对象的数量和大小:
在这里插入图片描述
由于内存中加载的对象可能很多,所以使用 | more 管道符,每次按一下空格可以多查看一页

对象的说明:
C 表示char类型
I 表示int类型
B 表示byte类型
F 表示float类型
J 表示long类型
Z 表示布尔类型
[ 表示数组类型 如[B 表示字节数组
[L+类名 表示其他对象

如果想过滤,只查看活跃对象,则可以添加live参数
jmap -histo:live 15304 | more
可以分页查询当前内存中的活跃对象

3.3:将jvm的运行情况dump到文件中进行分析

jmap -dump:format=b,file=d:/view_tomcat_heap.dat 15304
在这里插入图片描述
如果需要dump出活动的内存对象信息,则可以添加live参数:
jmap -dump:live,format=b,file=d:/view_tomcat_heap.dat 15304
这个命令将堆内存数据导出到指定文件中,其中参数format=b 表示是以二进制字节流的形式进行dump的,如何查看内存导出信息,请看下一节。

3.4:分析dump文件

3.4.1 使用jhat命令进行分析

示例:
jhat -port 7000 d:/view_tomcat_heap.dat
在这里插入图片描述
指定端口号,查看dump文件信息
现在打开浏览器,输入127.0.0.1:7000访问
可以看到页面显示信息
在这里插入图片描述
显示的是当前加载的类对象,点击进入可以查看更详细的类加载情况。
拉倒当前页面最下面,可以看到,有一个OQLquery的链接
在这里插入图片描述
OQL query
可以像查询sql一样查询符合条件的内存对象:
在刚才的页面,点击OQL qurey的查询链接,进入页面
在这里插入图片描述
目前我们还不会OQL可以点击下面的OQL Help,进入帮助页面查看怎么写OQL,页面中提供了一些示例;
查看帮助后,可以写一段试试
select s from java.lang.String s where s.value.lenth>=100
然后点击下方的excute按钮
在这里插入图片描述
查出字符串长度大于等于100的对象,然后可以点击进去查看对象的内容,查看是否是合理的,如果在调试问题的时候,就可以以此进行调节或者调整。

3.4.2 通过MAT工具进行dump分析

MAT工具介绍
Memory Analyzer tool
一个基于eclipse的内存分析工具,是一个快速的、功能丰富的java堆内存分析工具

需要先去官网下载mat工具,然后解压zip压缩包,在打开的压缩包中找到MemoryAnalizer.exe,双击即可启动分析工具
分析工具是分析dump文件的,所以打开分析工具后,可以点击文件-打开,选择我们的dump文件,打开,即可查看我们dump出来的程序运行的内存的快照。
MAT工具的具体用法,此处不详细介绍了。
待完善

4、用jstack查看线程情况

jstatck pid
例:jstack 15304
将正在运行的jvm的线程的快照打印出来
在这里插入图片描述
可以看到,会打印出来很多线程的执行情况,以及该线程当前的状态,有waiting、timed_watiting、running等,

4.1:线程的状态

正常java的线程的状态有以下几种:
在这里插入图片描述
new:初始态
running:运行中
ready:准备就绪
waiting:等待
timed_waiting:超时等待
blocked:阻塞状态
终止

4.2:jstack pid 命令

其中pid是jvm的线程id
可以查看线程情况,比如出现程序没反应了,停止不动了等情况,可查看是否有线程死锁的情况发生。

5、VisualVM工具

前面介绍了一些常用的命令行工具,下面出场的是java自带的图形化分析工具:jvisualvm.exe
在java安装目录下的bin目录中,直接双击jvisualvm.exe即可打开分析工具。
在这里插入图片描述
在这里插入图片描述
它包含了前文提供的几乎所有的命令行的功能:查看正在运行的jvm列表;查看堆内存使用情况;查看线程使用情况;监视jvm运行状态,包括cpu占用、内存占用、类加载、线程情况等;执行垃圾回收;dump内存快照;分析dump文件等功能

5.1:查看本地jvm进程的执行情况

打开jvisualvm后默认就将本地jvm加载进来,直接可以查看

5.2:查看远程jvm进程的执行情况

jvisualvm不仅仅可以监控本地进程,还可以监控远程服务器上的jvm的运行情况,需要借助于jmx技术

5.2.1:什么是JMX

JMX(java management extensions,即java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。

5.2.2:监控远程tomcat

1:在远程tomcat中开放jmx
需要在远程tomcat服务添加一些参数,让其开放jmx
在tomcat的bin目录中修改catalina.sh添加参数:

CATALINA_OPTS=-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false”

保存并重新启动tomcat,即可
这几个参数的意思是:
-Dcom.sun.management.jmxremote 允许使用JMX远程管理
-Dcom.sun.management.jmxremote.port=9999 远程管理的端口是9999
-Dcom.sun.management.jmxremote.ssl=false 是否启用ssl认证(这里为了简化没有启用,所以设置为false)
-Dcom.sun.management.jmxremote.authenticate=false 是否使用身份认证(这里设置false即不需要身份认证)

如果需要设置安全认证的相关参数,参考这篇博文:
https://blog.csdn.net/dongdong2980/article/details/78476393

https://blog.csdn.net/dongdong2980/article/details/78476393

2:本地visualvm添加远程服务器
在界面中,右击远程,添加远程主机,输入主机ip,添加主机
在这里插入图片描述
右击远程主机,添加JMX连接
在这里插入图片描述
填写jmx参数
在这里插入图片描述
点击确定,添加远程JMX,此时监控远程主机的操作和监控本地jvm操作基本一样(注意,如果是dump堆内存快照的话,是dump到远程主机中,需要从远程主机中下载到本地,再通过 文件 -> 装入,打开dump文件)

6、总结

本文主要内容包括:
JVM运行参数,重点掌握非标准运行时参数如: -XX:NewRetio -Xms 和 -Xmx等
JVM的堆内存组成——JDK1.7和1.8的不同
使用jps查看jvm进程号
使用jstat 查看堆内存的使用
使用jmap查看内存的详情
使用jmap -dump 将堆内存的快照导出到文件
使用jhat 分析dump文件,排查内存溢出等异常
使用MAT工具分析dump文件
使用jstack分析jvm中的线程情况,排查线程死锁等问题

VisualVM工具的使用,使用visualVM,可以查看基本上所有以上通过命令行能做到的事情。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值