JVM内存模型剖析

JDK体系结构

 Java语言的跨平台特性

JVM内存模型

Java虚拟机内部分成三部分:类装载子系统,运行时数据区(内存模型),字节码执行引擎。

运行时数据区包含有:本地方法栈,线程栈,堆,方法区(元空间),程序计数器

线程栈开辟一个内存空间用来存放线程的,一个线程若对应有多个方法,每个方法会对应在内存空间中分配一个小区域栈贞给到方法

每个栈贞中会存放:局部变量,操作数栈(方法内部的操作在该栈执行),动态连接(方法内部调用其他方法时,指向被调用方法的真实存放地址),方法出口。

程序计数器:每个线程在执行的过程中,方法执行的每一步都会有程序计数器进行计数标记,而字节码执行引擎就是动态修改程序计数器计数的

堆:用于存放新创建的对象,其中线程栈中存放有该新创建对象的引用地址

方法区(元空间):存放的是,静态变量,类信息,其中方法区中也存放有新创建对象的引用地址。

本地方法栈:主要是调用本地方法的从而分配内存空间,本地方法主要是与C语言交互的常量

注意:其中方法区(元空间)是所有线程共享的内存,

eg:

以上代码运行后,可看到java所谓的汇编语言结果:此处需要参照JVM指令手册

堆内存分配:

年轻代和老年代的占比=1:2

年轻代:包含有Eden区和survior区(s0,s1)占比是(Eden:s0:s1=8:1:1)

Minor gc : 主要是回收年轻代区域的内存。

Fullgc: 主要回收所有区域的内存,在进行fullgc是会进行stw(stop the work)操作,停止用户线程

JVM内存参数设置

Spring Boot程序的JVM参数设置格式(Tomcat启动直接加在bin目录下catalina.sh文件里):
java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar microservice‐eurek
a‐server.jar
关于 元空间的JVM参数 有两个: -XX:MetaspaceSize=N和 -XX:MaxMetaspaceSize=N
-XX:MaxMetaspaceSize 设置元空间最大值, 默认是-1, 即不限制, 或者说只受限于本地内存大小。
-XX:MetaspaceSize 指定元空间触发Fullgc的初始阈值(元空间无固定初始大小), 以字节为单位, 默认是21M ,达到该值就会触发 full gc进行类型卸载, 同时收集器会对该值进行调整: 如果释放了大量的空间, 就适当降低该值; 如果释放了很少的空间, 那么在不超过-XX:MaxMetaspaceSize(如果设置了的话) 的情况下, 适当提高该值。
这个跟早期jdk版本的-XX:PermSize参数意思不一样,- XX:PermSize 代表永久代的初始容量。
        由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量Full GC,通常都是由于永久代或元空间发生 了大小调整,基于这种情况, 一般建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样的值 ,并设置得比初始值要大,
对于8G物理内存的机器来说,一般我会将这两个值都设置为256M。

StackOverflowError示例:

// JVM设置 ‐Xss128k(默认1M)
public class StackOverflowTest {

    static int count = 0;

    static void redo() {
        count++;
        redo();
    }

    public static void main(String[] args) {
        try {
            redo();
        } catch (Throwable t) {
            t.printStackTrace();
            System.out.println(count);
        }
    }
}

运行结果:
java.lang.StackOverflowError
    at com.tuling.jvm.StackOverflowTest.redo(StackOverflowTest.java:12)
    at com.tuling.jvm.StackOverflowTest.redo(StackOverflowTest.java:13)
    at com.tuling.jvm.StackOverflowTest.redo(StackOverflowTest.java:13)
结论:
-Xss设置越小count值越小,说明一个线程栈里能分配的栈帧就越少,但是对JVM整体来说能开启的线程数会更多