结构图
注:蓝色为线程私有,黄色为线程共享
栈
重要特性
- 线程私有
- 先进后出
图例
概念
栈帧
栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用至执行完成的过程,都对应着一个栈帧在虚拟机栈里从入栈到出栈的过程。
局部变量表
它是一组变量值存储空间,用于存放方法参数和方法内定义的局部变量。
操作数栈
操作数栈在方法执行期间用于存储操作数,并在执行指令时作为输入和输出数据的来源。
动态链接
将符号引用转为直接引用
方法出口
当一个方法开始执行时,可能有两种方式退出该方法:
- 正常完成出口
- 异常完成出口
无论方法采用何种方式退出,在方法退出后都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在当前栈帧中保存一些信息,用来帮他恢复它的上层方法执行状态。
本地方法栈
用于支持native方法的执行。在Java HotSpot虚拟机中,它与Java虚拟机栈合并。
堆
由年轻代、老年代组成(1:2,可调)。
概念
年轻代
默认占三分之一,包含Eden区和幸存1区和2区(8:1:1)。
Eden区
默认开始存放位置
幸存区
当执行minor gc(STW时间短)时,会将不可回收对象放到幸存区(gcroot引用的)分代+1,大的直接放在老年代。
老年代
默认占三分之二,分代次数多的(默认为15次)或者内存多的会移到老年代。
当老年代满的时候,会触发full gc(STW时间长,重点优化对象),尝试回收,如果发现仍然回收不了最终触发OOM(严重)。
方法区(元空间)
使用直接内存,常量+静态变量+类信息
JVM内存参数设置
示例:java -Xms2048M -Xmx2048M -Xmn1024M -Xss512k -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar xxx.jar
栈参数设置
默认为1M,一般设置为512k或1M就可以了。
-Xss设置的越小,对JVM来说能开启的线程数越多。
元空间参数设置
关于元空间的JVM参数有两个: -XX:MetaspaceSize=N和-XX:MaxMetaspaceSize=N,对于64位JVM来说,元空间的默认初始大小是21MB,默认的元空间的最大值是无限
-XX: MaxMetaspaceSize: 设置元空间最大值,默认是-1,即不限制,或者说只受限于本地内存大小。
-XX:MetaspaceSize指定元空间的初始空间大小,以字节为单位,默认是21M,达到该值就会发 进行类型卸载,同时收集器会对该值进行调整:如果释放了大量的空间,就适当降低该值,如果释放了很少的空间,那么在不超过-XX: MaxMetaspaceSize(如果设置了的话) 的情况下,适当提高该值。
由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量Full GC,通常都是由于永代或元空间发生了大小调整,基于这种情况,一般建议在VM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样的值,并设置得比初始值要大,对于8G物理内存的机器来说,一般我会将这两个值都设置为256M
优化案例
每秒产生60MB对象,并在1S后变为垃圾对象。
如上图所示,就会导致垃圾对象占用老年代导致频繁full gc的情况,这个时候就要通过-Xmn参数扩大年轻代,或扩大幸存区。
优化后效果:
当然上述只供参考,实际要根据真实项目来,并大量测试。