暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一次搞懂JVM

杨遥 2020-12-31
255

                                                                                              作者|杨遥


JVM是什么


JVM它是Java Virtual Machine 的缩写,主要是通过在实际计算机模仿各种计算机功能来实现的,组成部分包括堆区、栈区、本地方法栈、方法区(元空间)、程序计算器等


堆区

JAVA运行是数据区管理内存最大的一块,线程共享,对象大多数由此产生,GC主要发生在这一块区域,也是JVM调优最重要的部分。
堆区主要分为年轻代和老年代,默认比为1:2。年轻带包含Eden伊甸园区和Survivor区,Survivor分为S0区和S1区,Eden:S0:S1=8:1:1。
对象由Eden区产生,大部分朝生夕死。年轻代的GC又叫minorGC,对象Eden产生,到Eden快满时候进行年轻的GC,minorGC后会将存活的对象放到S0区。若S0区放不下,一些大对象直接进入到老年代。下一次MinorGC将会Eden和S0区一起进行垃圾回收,将存活的对象挪到S1区域,此时S0和S1互换身份,所以年轻代的GC非常适合复制算法,当对象达到一定年龄时(MinorGC多次后,对象任然存活,默认是15次),将进入老年代。
当老年快满的时候,将进行FullGC,此时会对整个堆进行GC操作,将会STW,所以我们一般尽量减少FullGC,一般几天一次或者几周一次。

附阿里一道面试题:理论上能使得JVM永远不产生FullGC吗?
答案是肯定的,只要大部分对象都在minorGC被销毁,并发情况下产生的大对象不足以直接进入老年代是完全可以做到的。


栈区


栈区主要存放4个东西:局部变量表操作数栈动态链接方法出口

局部变量表

比如我们一个方法有int a =1; int b =2 ; int c =a+b;这段代码

这些变量是不是需要内存来存放,局部变量表主要是存放以下内容

操作数栈


操作数栈主要是用来操作JAVA代码计算的过程。如上代码javap反编译后就是这样子

0:iconst_1

1:istore_1

2:iconst_2

3:istore_2

4:iconst_3

5:iadd

查官方手册之后就是iconst_1定义常量1,istore_1存储常量1也就是a=1的过程吧,iadd就是把a和b相加,相加的过程主要是通过操作数栈来完成这么一个过程。所以你可以直接理解操作数栈就是JAVA计算变量的一个过程,计算完成之后,出栈,销毁。



动态链接


程序运行的时候可能依赖其他类,而此时只是一个符号引用,动态链接的就是把符号引用转换成直接引用。下次需要的时候直接找到内存地址。


方法出口

 一个简单例子,一个main方法调用一个test方法,之后输出1的过程。
        public static void main(String[] args) {
    test();
    System.out.println(1);
        }
    private static void test() {
    System.out.println("test方法");
    }

    首先main方法入栈,然后test方法入栈,test执行完之后,test出栈释放内存,程序怎么知道我接口代码该回到那里呢,这时候就需要方法出口记录了,执行完test方法后还能回到输出语句继续执行。图解应该是下面这样的

    本地方法栈


    底层主要是C语言或者C++实现,由JAVA直接调用方法,如native修饰的方法


    方法区(元空间)


    JDK7以前方法区属于运行时数据区。到了JDK8改名叫元空间,使用的直接物理内存。主要存放一些类加载信息,静态变量,常量等。


    程序计数器


    线程私有,可以直接理解为当前线程执行代码的行号。现在我们的系统都是多核的,可能一个线程没有执行完当前代码,被其他线程抢占了CPU,等到再次抢到cpu时,能继续接着上次执行。


    文章转载自杨遥,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论