JVM内存模型
# JVM内存模型
# 栈
# 虚拟机栈(方法栈)
虚拟机栈是每个线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的时候都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接信息、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中的入栈到出栈的过程。
# 操作数栈
操作数栈是虚拟机栈中的一个组成部分,存在于每个栈帧内。它主要用于存储操作指令的操作数以及指令执行的结果。操作数栈是一个后进先出(LIFO)的栈结构,它帮助执行Java字节码指令,比如算术运算和方法调用等。
# 数据结构
尽管两者都是栈结构,操作数栈和虚拟机栈的数据结构在用途上有所不同:
- 虚拟机栈:包含一个或多个栈帧,每个栈帧对应一个方法调用。
- 操作数栈:仅存在于栈帧中,用于存储临时数据和计算过程中的中间结果。
# 操作数栈与局部变量表的交互
操作数栈和局部变量表是栈帧中两个独立的组件。它们的交互如下:
- 操作数加载和存储:操作指令可以将局部变量表中的变量加载到操作数栈中,或者将操作数栈顶的值存储到局部变量表中。这通过
load
和store
指令族实现。 - 方法调用和返回值处理:在方法调用时,参数从局部变量表传递到操作数栈中,然后进行方法调用。方法返回时,返回值会被推到调用者的操作数栈顶。
# 实例
以下是一些字节码操作的示例,显示了操作数栈和局部变量表的交互:
iload_0
:将局部变量表中第一个整型变量推送到操作数栈顶。istore_1
:将操作数栈顶的整型值弹出,存储到局部变量表的第二个位置。
这些指令显示了操作数栈不是简单地将数据“转移”到局部变量表,而是根据需要进行加载和存储操作。这种设计使得JVM可以灵活地执行各种运算并处理方法间的数据传递。
# 一、JVM内存参数
-Xss:每个线程栈大小
-Xms:初始堆大小,默认物理内存的1/64
-Xmx:最大堆大小,默认物理内存的1/4
-Xmn:新生代大小
-XX:NewSize:设置新生代初始大小
-XX:NewRatio:默认2表示新生代占年老代的1/2,占整个堆内存的1/3
-XX:SurvivorRatio:默认8表示一个survivor区占用1/8的Eden内存,即1/10的新生代内存
2
3
4
5
6
7
-XX: MaxMetaspaceSize :设置元空间最大值,默认值 -1即不限制,只受限于本地内存大小,元空间无固定初始大小
-XX: MetaspaceSize : 指定元空间(方法区)触发FullGC的初始阈值,以字节为单位,默认是21M,达到该值会触发Full GC进行类型卸载,同事收集器会对该值进行调整:如果释放了大量空间,就适当降低该;如果释放了少量空间,在不超过-XX:MaxMetaspaceSize(如果设置了元空间最大值)的情况下,适当提高该值,这个跟早期jdk版本的-XX:PermSize参数意思不一样,- XX:PermSize代表永久代的初始容量。
提示
# 由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动时发生大量Full GC,一般是由于永久代或元空间发生了大小调整,基于这种情况,一般建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样,并设置的比触发Fullgc阈值初始值(21M)要大,对于8G的物理机,一般建议设置256M
注意
# 结论:尽可能让对象都在新生代里分配和回收,尽量别让太多的对象频繁进入老年代,避免频繁对老年代进行垃圾回收,同时给系统充足的内存大小,避免新生代频繁的进行垃圾回收
# 二、Minor GC ,Full GC 触发条件
Minor GC触发条件:
当Eden区满时,触发Minor GC。
Full GC触发条件:
- 调用System.gc时,系统建议执行Full GC,但是不必然执行
- 老年代空间不足(达到75%或者设定值)
- 方法区空间不足
- 通过Minor GC后进入老年代的平均大小大于老年代的可用内存(对象动态年龄判断)
- 由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小
- 空间担保机制触发
# 三、常用参数
# 1、标准参数
-version
-help
-server
-cp
2
3
4
# 2、-XX参数
a.Boolean类型
格式: -XX:[+-]<name> +或-表示启用或者禁用name属性
比如: -XX:+UseConcMarkSweepGC 表示启用CMS类型的垃圾回收器
-XX:+UseG1GC 表示启用G1类型的垃圾回收器
b.非Boolean类型
格式:-XX<name>=<value>表示name属性的值是value
比如:-XX:MaxGCPauseMillis=500
2
3
4
5
6
7
8
# 3、其他参数
-Xms1000 等价于 -XX:InitialHeapSize=1000
-Xmx1000 等价于 -XX:MaxH eapSize=1000
-Xss100 等价于 -XX:ThreadStackSize=100
2
3
# 4、查看参数
java -XX:+PrintFlagsFinal -version > flflags.txt
java -XX:+PrintFlagsFinal:查看所有JVM参数启动的初始值
java -XX:+PrintCommandLineFlags:查看那些已经被用户或者JVM设置过的详细的xx参数的名称和值。
2
3
4
“=” 表示默认值,“:=”表示被用户或JVM修改的值
- jinfo -flags pid :查看jvm的参数
- jinfo -sysprops pid:查看jvm的参数
# 5、设置参数方式
- IDEA 中通过 VMoption
- 运行jar包,java -XX:+UseG1GC xxx.jar
- web 容器可以在脚本中设置
- 通过 jinfo 动态调整某个java进程的参数(参数被标记manageable的flags可以被修改)
# 6、单位换算
1MB=1024KB=1048576 byte(字节)
1G=1024M=1048576 KB
1TB=1024GB
1GB=1024MB
1MB=1024KB
1KB=1024Byte
1Byte=8bit
例如:-XX:MaxHeapSize=262144000 (byte) 262144000/1024 = 25600 (kb) 25600/1024 = 250 (Mb)
2
3
4
5
6
7
8
9
# 7、常用参数
参数 | 含义 | 说明 |
---|---|---|
-XX:CICompilerCount=3 | 最大并行编译数 | 如果设置大于1,编译速度提高,稳定性下降 |
-XX:InitialHeapSize=100M | 初始化堆大小 | 简写-Xms100M |
-XX:MaxHeapSize=100M | 最大堆大小 | 简写-Xmx100M |
-XX:NewSize=20M | 设置新生代的大小 | |
-XX:MaxNewSize=40M | 新生代最大大小 | |
-XX:OldSize=50M | 设置老年代大小 | |
-XX:MetaspaceSize=50M | 设置方法区大小 | |
-XX:MaxMetaspaceSize=50M | 方法区最大大小 | |
-XX:+UseParallelGC | 使用ParallelGC | 新生代,吞吐量优先 |
-XX:+UseParallelOldGC | 使用ParallelOldGC | 老年代,吞吐量优先 |
-XX:+UseConcMarkSweepGC | 使用CMS | 老年代,停顿时间优先 |
-XX:+UseG1GC | 使用G1 | 新老年代,停顿时间优先 |
-XX:NewRatio | 新老比值 | 例:-XX:NewRatio=4,则新:老=1:4,新生代占用堆内存的1/5 |
-XX:SurvivorRatio | 两个S区和Eden区的比值 | 例:-XX:SurvivorRatio=8,就是(S0+S1):Eden=2:8, |
-XX:+HeapDumpOnOutOffMemoryError | 启动堆内存溢出打印 | 当堆内存发生溢出(OOM)时,自动生成dump文件 |
-XX:HeapDumpPath=heap.hprof | 指定堆内存溢出打印的目录 | 表示在当前目录生成一个heap.hprof文件 |
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps –Xloggc:log/gc.log | 打印GC日志 | 可以使用不同的垃圾收集器,对比查看GC的情况 |
=-Xss128k | 设置每个线程的堆栈大小 | 经验值是3000-5000最佳 |
-XX:MaxTenuringThreshold=6 | 提升老年代的最大临界值 | 默认值为15 |
-XX:InitiatingHeapOccupancyPercent | 启动并发GC周期时堆内存使用占比 | G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆 的使用率,0代表”一直执行GC循环“ 默认值为45 |
-XX:G1HeapWastePercent | 允许的浪费堆空间占比 | 默认值为10%,如果并发标记可回收的空间小于10%,则不会触发MixedGC |
-XX:MaxGCPauseMillis=200ms | G1最大停顿时间 | 停顿时间不能太小,太小会导致G1跟不上垃圾生成的速度,会触发Full GC。 |
-XX:ConcGCThreads=n | 并发垃圾收集器的使用线程数 | 默认值根据JVM的运行平台设置 |
-XX:G1MixedGCLiveThresholdPercent=65 | 混合垃圾回收周期中要包含的旧区域设置占用阈值 | 默认占用率为65% |
-XX:G1MixedGCCountTarget=8 | 设置标记周期完成后,对存活数据上限为G1MixedGCLiveThresholdPercent的旧区域执行混合垃圾回收的目标次数 | 默认8次混合垃圾回收,混合垃圾回收的目标主要控制在此目标书以内 |
-XX:G1OldCSetRegionThresholdPercent=1 | 描述Mixed GC时,Old Region 被加入到CSet中 | 默认情况下,G1只把10%的Old Region加入到CSet中 |