JVM
文章目录
参数
- 标准参数(-),所有的JVM实现都必须实现这些参数的功能,java -help
- 非标准参数(-X),默认jvm实现这些参数的功能,java -X
- 非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消
内存模型
栈
是运行时的单位,而堆
是存储的单位。
堆中存的是对象
,栈中存的是基本数据类型
和堆中对象的引用
堆(Heap)
-
新生代(Young)
Eden:新对象,装满触发YGC,依然存活会转移到S区
Survivor(S0+S1) -
老年代(Old)
装满触发FGC,依然无法放下,抛出OOM
默认内存比例:新生代1/3(E:4/5, S:1/5);老年代2/3
栈(Stack)
先进后出的数据结构,每个方法从开始调用到执行完成的过程,就是栈帧从入栈到出栈的过程
栈帧包括:局部变量表、操作栈、动态连接、方法返回地址等(一个方法对应一块栈帧内存区域)
- 程序计数器:JVM指令码执行到的行号
- 本地方法栈(native):
System.currentTimeMillis()
场景:逆序输出、汉诺塔、数制转换
元空间(Metaspace)
JDK8开始,本地内存分配
存储包括:类元信息、字段、静态属性、方法、常量等
JVM运行时内存
年轻代(Young Generation)
所有新生成的对象首先都是放在年轻代的,年轻代分三个区:一个 Eden 区,两个 Survivor 区(S0,S1)。当 Eden 区满时,还存活的对象将被复制到 Survivor 区。
年老代(Old Generation)
在年轻代中经历了 N 次垃圾回收后仍然存活的对象,就会被放到年老代中。
持久代(Permanent Generation)
用于存放静态文件,如今 Java 类、方法等。
-XX:MaxPermSize=16m:设置持久代大小为 16m。
注:JDK1.8之后已经没有持久代的概念了,改为元数据 MetaspaceSize | MaxMetaspaceSize
总结
-Xms2048m:设置 JVM 初始内存为 2048m。此值可以设置与-Xmx 相同,以避免每次垃圾回
收完成后 JVM 重新分配内存。默认物理内存的 1/64。
-Xmx2048m:设置 JVM 最大可用内存为 2048m。默认物理内存的 1/4。
-Xmn1g:设置年轻代大小为 1G。堆大小 = 年轻代大小 + 年老代大小 + 持久代大小。
-XX:NewRatio=4:设置年轻代(包括 Eden 和两个 Survivor 区)与年老代的比值(除去持久代)。设置为 4,则年轻代与年老代所占比值为 1:4,年轻代占整个堆栈的 1/5
-XX:SurvivorRatio=4:设置年轻代中 Eden 区与 Survivor 区的大小比值。
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m :设置元空间大小,设置成一样
-Xss128k:设置每个线程的堆栈大小。
垃圾回收
Minor GC
从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC
当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。所以分配率越高,越频繁执行 Minor GC
Major GC
Major GC 是清理老年代
Mixed GC
是在G1收集器中独有的,用于收集整个young gen以及部分old gen的GC
Full GC
清理整个堆空间—包括年轻代、老年代及永久代(元数据空间)
GC日志
[GC (Allocation Failure) [ParNew: 367523K->1293K(410432K), 0.0023988 secs] 522739K->156516K(1322496K), 0.0025301 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
Allocation Failure:表明本次引起GC的原因是因为在年轻代中没有足够的空间能够存储新的数据了
ParNew:表明本次GC发生在年轻代并且使用的是ParNew垃圾收集器
367523K->1293K(410432K):单位是KB,三个参数分别为:GC前该内存区域(这里是年轻代)使用容量,GC后该内存区域使用容量,该内存区域总容量。
522739K->156516K(1322496K):三个参数分别为:堆区垃圾回收前的大小,堆区垃圾回收后的大小,堆区总大小。
[Times: user=0.04 sys=0.00, real=0.01 secs]:分别表示用户态耗时,内核态耗时和总耗时
垃圾回收器
串行收集器、并行收集器、并发收集器
串行收集器Serial
Serial收集器会冻结所有应用程序线程(SWT),使用单个垃圾回收线程来进行垃圾回收工作,新生代、老年代使用串行回收;新生代复制算法、老年代标记-压缩
-XX:+UseSerialGC
默认情况下,JDK5.0,以前都是使用串行收集器
ParNew收集器是Serial收集器的多线程版本,新生代并行,老年代串行;新生代复制算法、老年代标记-压缩
-XX:+UseParNewGC
并行收集器Parallel
Parallel收集器更关注系统的吞吐量,新生代复制算法、老年代标记-压缩【jdk8默认】
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置
下,年轻代使用并发收集,而年老代仍旧使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾
回收。此值最好配置与处理器数目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0 支持对年老代并行
收集。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为 1/(1+n)
并发收集器CMS
是一种以获取最短回收停顿时间为目标的收集器,基于“标记-清除”算法实现
-XX:+UseConcMarkSweepGC:使用CMS收集器
-XX:ParallelCMSThreads:设定CMS的线程数量
-XX:+UseCMSCompactAtFullCollection:Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
-XX:+CMSFullGCsBeforeCompaction:设置进行几次Full GC后,进行一次碎片整理
-XX:+CMSIncrementalMode:设置为增量模式。适用于单 CPU 情况。
G1收集器
特点:空间整合(采用标记整理算法,不会产生内存空间碎片)、可预测停顿【jdk9+默认】
-XX:+UseG1GC
垃圾回收统计信息
-XX:+PrintGC 打印GC日志
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:gc.log 输出到文件✅
-XX:-DisableExplicitGC 禁用System.gc()的显示调用
查看GC类型: java -XX:+PrintCommandLineFlags -version
命令
jps
JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
-l : 输出主类全名或jar路径
-q : 只输出LVMID
-m : 输出JVM启动时传递给main()的参数
-v : 输出JVM启动时显示指定的JVM参数
jstat
用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
jstat [option] LVMID
[option] : 操作参数
LVMID : 本地虚拟机进程ID
示例:
jstat -class 12709 # 监视类装载、卸载数量、总空间以及耗费的时间
jstat -gc 12709 # 垃圾回收堆的行为统计
Option | Displays |
---|---|
class | class loader的行为统计。 |
compiler | HotSpt JIT编译器行为统计。 |
gc | 垃圾回收堆的行为统计。 |
gccapacity | 各个垃圾回收代容量(young,old,perm)和他们相应的空间统计。 |
gcutil | 垃圾回收统计概述。 |
gccause | 垃圾收集统计概述(同-gcutil),附加最近两次垃圾回收事件的原因。 |
gcnew | 新生代行为统计。 |
gcnewcapacity | 新生代与其相应的内存空间的统计。 |
gcold | 年老代和永生代行为统计。 |
gcoldcapacity | 年老代行为统计。 |
gcpermcapacity | 永生代行为统计。 |
printcompilation | HotSpot编译方法统计。 |
gc列详解:见附件一
jmap
用于生成heap dump文件,如果不使用这个命令,还阔以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候·自动生成dump文件。
jmap [option] LVMID
dump : 生成堆转储快照
finalizerinfo : 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
heap : 显示Java堆详细信息
histo : 显示堆中对象的统计信息
permstat : to print permanent generation statistics
F : 当-dump没有响应时,强制生成dump快照
示例:
jmap -dump:live,format=b,file=dump.hprof 12709 # dump堆到文件,format指定输出格式,live指明是活着的对象,file指定文件名
jmap -heap 12709 # 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况,可以用此来判断内存目前的使用情况以及垃圾回收情况
jmap -histo:live 28920 | more # 打印堆的对象统计,包括对象数、内存大小等等
*内存不足或泄露导出堆栈:-XX:+HeapDumpOnOutOfMemoryError
*可以使用mat或headAnalyze打开
jhat
与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看
jhat [dumpfile]
示例:
jhat -J-Xmx512m dump.hprof
*jdk11已废弃
jstack
生成java虚拟机当前时刻的线程快照。
jstack [option] LVMID
-F : 当正常输出请求不被响应时,强制输出线程堆栈
-l : 除堆栈外,显示关于锁的附加信息
-m : 如果调用到本地方法的话,可以显示C/C++的堆栈
示例:
jstack -l 12709 | more
jinfo
实时查看和调整虚拟机运行参数
-flag : 输出指定args参数的值
-flags : 不需要args参数,输出所有JVM参数的值
-sysprops : 输出系统属性,等同于System.getProperties()
示例:
jinfo -flags 12709
javap
查看一个java类反汇编、常量池、变量表、指令代码行号表等等信息
javap -c -l xxx.class
JDK10+新增
- jshell
- jhsdb hsdb|jmap --|jinfo --|jstack –
- jcmd pid help
线程的状态
Java中线程的状态分为6种
- 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
- 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。 线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
- 阻塞(BLOCKED):表示线程阻塞于锁。
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
- 终止(TERMINATED):表示该线程已经执行完毕。
JMX和DEBUG
DEBUG
启动命令添加: java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar xxx.jar
IDEA Run Configurations选择Remote -> 填写IP和端口,选择模块,点击启动按钮 -> 在需要的行打上断点。
JMX
启动命令添加: java -Dcom.sun.management.jmxremote.port=18888 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=192.168.40.200 -jar xxx.jar
案例
# 查看占用内存过高的进程
top
# 查看进程占用的具体资源
top -H -p10000 (10000是Java进程的PID)
# 线程堆栈信息
jstack 10001 > jstack.txt
# GC运行信息
jstat -gcutil 10000 2000 10
# 内存占用信息
jmap -histo 10000 | more
附件一
S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC:年轻代中Eden(伊甸园)的容量 (字节)
EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
OC:Old代的容量 (字节)
OU:Old代目前已使用空间 (字节)
PC:Perm(持久代)的容量 (字节) [MC]
PU:Perm(持久代)目前已使用空间 (字节) [MU]
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
NGCMN:年轻代(young)中初始化(最小)的大小 (字节)
NGCMX:年轻代(young)的最大容量 (字节)
NGC:年轻代(young)中当前的容量 (字节)
OGCMN:old代中初始化(最小)的大小 (字节)
OGCMX:old代的最大容量 (字节)
OGC:old代当前新生成的容量 (字节)
PGCMN:perm代中初始化(最小)的大小 (字节)
PGCMX:perm代的最大容量 (字节)
PGC:perm代当前新生成的容量 (字节)
S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
O:old代已使用的占当前容量百分比
P:perm代已使用的占当前容量百分比
S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节)
S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节)
ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)
DSS:当前需要survivor(幸存区)的容量 (字节)(Eden区已满)
TT: 持有次数限制
MTT : 最大持有次数限制