文章目录
三种参数类型
jvm的参数类型分为三类,分别是:
- 标准参数
-help
-version - -X参数 (非标准参数)
-Xint
-Xcomp - -XX参数(使用率较高)
-XX:newSize
-XX:+UseSerialGC
标准参数
jvm的标准参数,一般都是很稳定的,在未来的JVM版本中不会改变,可以使用java -help
检索出所有的标准参数。
实战
实战1:查看jvm版本
实战2:通过-D设置系统属性参数
public class TestJVM {
public static void main(String[] args) {
String str = System.getProperty("str");
if (str == null) {
System.out.println("yq");
} else {
System.out.println(str);
}
}
}
进行编译、测试:
# 编译
javac TestJVM.java
# 测试
java TestJVM
yq
# 设置参数测试
java -Dstr=James TestJVM
James
-server与-client参数(了解)
可以通过-server或-client设置jvm的运行参数。
- 它们的区别是Server VM的初始堆空间会大一些,默认使用的是并行垃圾回收器,启动慢运行快。
- Client VM相对来讲会保守一些,初始堆空间会小一些,使用串行的垃圾回收器,它的目标是为了让JVM的启动速度更快,但运行速度会比Serverm模式慢些。
- JVM在启动的时候会根据硬件和操作系统自动选择使用Server还是Client类型的JVM。
- 32位操作系统
– 如果是Windows系统,不论硬件配置如何,都默认使用Client类型的JVM。
– 如果是其他操作系统上,机器配置有2GB以上的内存同时有2个以上CPU的话默认使用server模式,否则使用client模式。 - 64位操作系统
– 只有server类型,不支持client类型。
测试:(#由于机器是64位系统,所以不支持client模式)
-X参数
jvm的-X参数是非标准参数,在不同版本的jvm中,参数可能会有所不同,可以通过java -X查看非标准参数。
-XX参数
-XX参数也是非标准参数,主要用于jvm的调优和debug操作。
-XX参数的使用有2种方式,一种是boolean类型,一种是非boolean类型:
- boolean类型
格式:-XX:[+-]<name>
表示启用或禁用<name>
属性
如:-XX:+DisableExplicitGC
表示禁用手动调用gc操作,也就是说调用System.gc()无效 - 非boolean类型
格式:-XX:<name>=<value>
表示<name>
属性的值为<value>
如:-XX:NewRatio=1
表示新生代和老年代的比值
java -showversion -XX:+DisableExplicitGC TestJVM
-Xms与-Xmx参数(重要)
-Xms:设置初始 Java 堆大小。
-Xmx:设置最大 Java 堆大小。
-Xmx2048m:等价于-XX:MaxHeapSize
,设置JVM最大堆内存为2048M。
-Xms512m:等价于-XX:InitialHeapSize
,设置JVM初始堆内存为512M。
适当的调整jvm的内存大小,可以充分利用服务器资源,让程序跑的更快。
java -Xms512m -Xmx2048m TestJVM
查看jvm的运行参数
运行java命令时打印参数:
# 参数有boolean类型和数字类型,值的操作符是=或:=,分别代表默认值和被修改的值。
java -XX:+PrintFlagsFinal -version
查看正在运行的jvm参数:
# 首先,启动一个tomcat用于测试,来观察下运行的jvm参数。
# 查看所有的参数,
# 用法:jinfo -flags <进程id>
# 通过jps 或者 jps -l 查看java进程
root@ubuntu:bin# jps
1698 Jps
1485 Bootstrap
root@ubuntu:bin# jps -l
1485 org.apache.catalina.startup.Bootstrap
1711 sun.tools.jps.Jps
root@ubuntu:bin# jinfo -flags 1485
Attaching to process ID 1485, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.141-b15
Non-default VM flags: -XX:CICompilerCount=2 -XX:InitialHeapSize=16777216 -XX:MaxHeapSize=262144000 -XX:MaxNewSize=87359488 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=5570560 -XX:OldSize=11206656 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps
Command line: -Djava.util.logging.config.file=/opt/apache-tomcat-7.0.57/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/opt/apache-tomcat-7.0.57/endorsed -Dcatalina.base=/opt/apache-tomcat-7.0.57 -Dcatalina.home=/opt/apache-tomcat-7.0.57 -Djava.io.tmpdir=/opt/apache-tomcat-7.0.57/temp
# 查看某一参数的值,用法:jinfo -flag <参数名> <进程id>
root@ubuntu:bin# jinfo -flag MaxHeapSize 1485
-XX:MaxHeapSize=262144000
jvm的内存模型
jdk1.7的堆内存模型
- Young 年轻区(代)
Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,其中,Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Eden区间变满的时候, GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到Tenured区间。 - Tenured 年老区
Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。 - Perm 永久区
Perm代主要保存class,method,filed对象,这部份的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。 - Virtual区:
最大内存和初始内存的差值,就是Virtual区。
jdk1.8的堆内存模型
由上图可以看出,jdk1.8的内存模型是由2部分组成,年轻代 + 年老代。
年轻代:Eden + 2*Survivor
年老代:OldGen
在jdk1.8中变化最大的Perm区,用Metaspace(元数据空间)进行了替换。
需要特别说明的是:Metaspace所占用的内存空间不是在虚拟机内部,而是在本地内存空间中,这也是与1.7的永久代最大的区别所在。
为什么要废弃1.7中的永久区?
通过jstat命令进行查看堆内存使用情况
jstat命令可以查看堆内存各部分的使用量,以及加载类的数量。命令的格式如下:
jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]
查看class加载统计
root@ubuntu:bin# jps
1939 Jps
1926 Bootstrap
root@ubuntu:bin# jstat -class 1926
Loaded Bytes Unloaded Bytes Time
2768 5470.3 0 0.0 1.74
说明:
- Loaded:加载class的数量
- Bytes:所占用空间大小
- Unloaded:未加载数量
- Bytes:未加载占用空间
- Time:时间
查看编译统计
root@ubuntu:bin# jstat -compiler 1926
Compiled Failed Invalid Time FailedType FailedMethod
1741 1 0 3.38 1 sun/misc/URLClassPath getResource
说明:
- Compiled:编译数量。
- Failed:失败数量
- Invalid:不可用数量
- Time:时间
- FailedType:失败类型
- FailedMethod:失败的方法
垃圾回收统计
root@ubuntu:bin# jstat -gc 1926
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
832.0 832.0 832.0 0.0 6976.0 3395.3 17256.0 15882.2 17024.0 16527.3 1920.0 1825.1 20 0.077 1 0.022 0.099
#也可以指定打印的间隔和次数,每1秒中打印一次,共打印5次
root@ubuntu:bin# jstat -gc 1926 1000 5
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
832.0 832.0 832.0 0.0 6976.0 4058.7 17256.0 15882.2 17024.0 16527.3 1920.0 1825.1 20 0.077 1 0.022 0.099
832.0 832.0 832.0 0.0 6976.0 4058.7 17256.0 15882.2 17024.0 16527.3 1920.0 1825.1 20 0.077 1 0.022 0.099
832.0 832.0 832.0 0.0 6976.0 4058.7 17256.0 15882.2 17024.0 16527.3 1920.0 1825.1 20 0.077 1 0.022 0.099
832.0 832.0 832.0 0.0 6976.0 4058.7 17256.0 15882.2 17024.0 16527.3 1920.0 1825.1 20 0.077 1 0.022 0.099
832.0 832.0 832.0 0.0 6976.0 4058.7 17256.0 15882.2 17024.0 16527.3 1920.0 1825.1 20 0.077 1 0.022 0.099
说明:
- S0C:第一个Survivor区的大小(KB)
- S1C:第二个Survivor区的大小(KB)
- S0U:第一个Survivor区的使用大小(KB)
- S1U:第二个Survivor区的使用大小(KB)
- EC:Eden区的大小(KB)
- EU:Eden区的使用大小(KB)
- OC:老年代区大小(KB)
- OU:老年代使用大小(KB)
- MC:方法区(永久代、元数据区)的大小(KB)
- MU:方法区(永久代、元数据区)的使用大小(KB)
- CCSC:压缩类空间大小(KB)
- CCSU:压缩类空间使用大小(KB)
- YGC:系统运行迄今为止的Young GC次数
- YGCT:Young GC总耗时
- FGC:系统运行迄今为止的Full GC次数
- FGCT:Full GC总耗时
- GCT:所有GC的总耗时
jmap的使用以及内存溢出分析
通过jstat可以对jvm堆的内存进行统计分析,而jmap可以获取到更加详细的内容,如:内存使用情况的汇总、对内存溢出的定位与分析。
查看内存使用情况
root@ubuntu:~# jps
1926 Bootstrap
2539 Jps
root@ubuntu:~# jmap -heap 1926
Attaching to process ID 1926, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.141-b15
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration: #堆内存配置信息
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 262144000 (250.0MB)
NewSize = 5570560 (5.3125MB)
MaxNewSize = 87359488 (83.3125MB)
OldSize = 11206656 (10.6875MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage: #堆内存使用情况
New Generation (Eden + 1 Survivor Space): #年轻代
capacity = 7995392 (7.625MB)
used = 5168944 (4.9294891357421875MB)
free = 2826448 (2.6955108642578125MB)
64.64903784579919% used
Eden Space:
capacity = 7143424 (6.8125MB)
used = 4931176 (4.702735900878906MB)
free = 2212248 (2.1097640991210938MB)
69.03098570097477% used
From Space:
capacity = 851968 (0.8125MB)
used = 237768 (0.22675323486328125MB)
free = 614200 (0.5857467651367188MB)
27.90809044471154% used
To Space:
capacity = 851968 (0.8125MB)
used = 0 (0.0MB)
free = 851968 (0.8125MB)
0.0% used
tenured generation: #年老代
capacity = 17670144 (16.8515625MB)
used = 17114592 (16.321746826171875MB)
free = 555552 (0.529815673828125MB)
96.85598487482615% used
12265 interned Strings occupying 1733688 bytes.
查看内存中对象数量及大小
#查看所有对象,包括活跃以及非活跃的
jmap -histo <pid> | more
#查看活跃对象
jmap -histo:live <pid> | more
root@ubuntu:~# jmap -histo:live 1926 | more
num #instances #bytes class name
----------------------------------------------
1: 32600 7228680 [C
2: 1579 1524392 [B
3: 30967 743208 java.lang.String
4: 2789 686136 [I
5: 17142 548544 java.util.HashMap$Node
6: 3082 350568 java.lang.Class
7: 5437 333184 [Ljava.lang.Object;
8: 3738 328944 java.lang.reflect.Method
9: 1020 206896 [Ljava.util.HashMap$Node;
10: 3105 99360 java.util.concurrent.ConcurrentHashMap$Node
11: 1127 96728 [Ljava.lang.String;
12: 1671 80208 java.util.HashMap
13: 3278 69952 [Ljava.lang.Class;
14: 63 66640 [Ljava.util.concurrent.ConcurrentHashMap$Node;
15: 2741 65784 java.util.ArrayList
16: 1570 62800 java.util.LinkedHashMap$Entry
17: 1271 61008 org.apache.tomcat.util.digester.CallMethodRule
18: 1671 53472 com.sun.org.apache.xerces.internal.xni.QName
19: 111 51696 [Ljava.util.WeakHashMap$Entry;
20: 1533 49056 java.util.Hashtable$Entry
21: 606 48480 java.lang.reflect.Constructor
22: 2896 46336 java.lang.Object
23: 1027 41080 java.util.TreeMap$Entry
24: 846 40608 org.apache.tomcat.util.modeler.AttributeInfo
25: 914 36560 java.lang.ref.SoftReference
26: 30 31200 [[C
27: 921 29472 java.lang.ref.WeakReference
28: 693 27720 java.lang.ref.Finalizer
29: 1001 24024 java.util.LinkedList$Node
30: 309 22248 java.util.logging.Logger
31: 155 20640 [Ljava.util.Hashtable$Entry;
32: 615 19680 javax.management.MBeanAttributeInfo
33: 537 17184 java.util.concurrent.locks.ReentrantLock$NonfairSync
--More--
#对象说明
B byte
C char
D double
F float
I int
J long
Z boolean
[ 数组,如[I表示int[]
[L+类名 其他对象
将内存使用情况dump到文件中
#用法:
jmap -dump:format=b,file=dumpFileName <pid>
#示例
root@ubuntu:~# jmap -dump:format=b,file=./dump.dat 1926
Dumping heap to /root/dump.dat ...
Heap dump file created
root@ubuntu:~# ls
dump.dat
root@ubuntu:~#
通过jhat对dump文件进行分析
将jvm的内存dump到文件中,文件是一个二进制的文件,不方便查看,这时我们可以借
助于jhat工具进行查看。
#用法:
jhat -port <port> <file>
#示例:
root@ubuntu:~# jhat -port 9999 ./dump.dat
Reading from ./dump.dat...
Dump file created Thu Jul 02 21:38:10 CST 2020
Snapshot read, resolving...
Resolving 158610 objects...
Chasing references, expect 31 dots...............................
Eliminating duplicate references...............................
Snapshot resolved.
Started HTTP server on port 9999
Server is ready.
打开浏览器进行访问:http://192.168.56.71:9999/
在最后面有OQL查询功能。
查询字符串长度大于10000的内容。
通过MAT工具对dump文件进行分析
-XX:NewSize=5242880 -XX:MaxNewSize=5242880 -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10485760 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log
-XX:NewSize 初始新生代大小
-XX:MaxNewSize 最大新生代大小
-XX:InitialHeapSize 初始堆大小
-XX:MaxHeapSize 最大堆大小
-XX:PretenureSizeThreshold=10485760 指定了大对象阈值是10MB
-XX:NewSize=104857600
-XX:MaxNewSize=104857600
-XX:InitialHeapSize=209715200
-XX:MaxHeapSize=209715200
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=15
-XX:PretenureSizeThreshold=20971520
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:gc.log
-Xms4096M -Xmx4096M -Xmn3072M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSParallelInitialMarkEnabled -XX:+CMSScavengeBeforeRemark
-Xms4096M
-Xmx4096M
-Xmn3072M
-Xss1M
-XX:PermSize=256M
-XX:MaxPermSize=256M
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=92
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSParallelInitialMarkEnabled
-XX:+CMSScavengeBeforeRemark
假设用默认的JVM参数,可能年轻代就几百MB的内存,Survivor区域就几十MB的内存
那么每次垃圾回收过后存活对象可能会有几十MB,这是因为在垃圾回收的一瞬间可能有部分请求没处理完毕,此时会有几十MB对象是存活的,所以很容易触发动态年龄判定规则,让部分对象进入老年代。
jstat显示出来的Full GC和Young GC的次数都是系统启动以来的总次数,耗时都是所有GC加起来的总耗时。
jstat -gc 1000 20
每隔一秒打印一次统计信息,连续打印20次
jmap -dump:live,format=b,file=F:\dump.hprof 6900