java架构之路-(十)JVM的运行时内存模型

   还是我们上次的图,我们上次大概讲解了类加载子系统的执行过程,验证,准备,解析,初始化四个过程。还有我们的双亲委派机制。

我们这次来说一下运行时内存模型。上一段小代码。

public class Main {
    public int compute() {
        int a = 11;
        int b = 22;
        int c = a + b / 2;
        return c;
    }

    public static void main(String[] args) {
        Main main = new Main();
        int result = main.compute();
        System.out.println(result);
        System.out.println(2);
    }
}

运行main方法时,再简单不过了,创建Main对象,调用compute方法,返回结果,打印,打印数字2。

那么这一系列过程在jvm里是怎么做的呢。我们来看一下。

1,为main方法开辟栈空间。

2,新建Main对象,放置在堆中。

3,开始运行compute对象,粗略的说开始计算

4,返回结果。

5,打印。

我再来详细的看一下内存模型内的栈到底是怎么工作的。

首先在栈空间内开辟一块空间,然后在空间内给予一个独立的main空间到栈底,在分配compute栈帧到栈,栈是先进后出的,切记。

 我们在对于compute的栈帧空间放大化来看一下。

 初始程序计数器为0也就是要运行第一行了,也就是说程序计数器就是控制代码该运行第几行的一个控制器。角标标识,从0开始。

int a = 11;就是首先将a放置在局部变量表中,(局部变量表如果需要存对象时,实则存储的是我们对象的引用)然后在操作数栈内生产11这个数字,再将11赋予a,则a=11放置在局部变量表内。并且计算过程是在操作数栈来做的。

方法出口是用来记录从哪里调用的,也就是方法出口指向了我们main方法。稍后去说我们的动态链接。

我们先来看一下我们的栈的大小,我们在程序启动时可以配置-xss=1M,这个1M其实每一个栈线程的大小,并不是代表全部的栈大小总和。

动态链接就是我们的一些列符号引用,当我们输入javap -v ***.class时,会生成一个常量池,#1,#2...都是一些符号引用的地址,这里把所有的参数名,方法名都可以理解为符号。

这样来说我们就把我们的栈,程序计数器,元空间之间的联系大概说了一遍。

我们在来看看我们的堆区

堆主要分为年轻代,老年代,元空间。年轻代又分为eden区,from区,to区。大概是8:1:1。

新建的对象一律防放置在eden区上,当我们的eden放置满的时候,会触发我们的minorGC,清理到那些不可达对象,也就是不在有可能使用的对象。处理完成之后会放置在from区域,当下次eden再次满时,我们会连同我们的from区域一起进行minorGC,然后将处理后的对象放置在to区域,这时to区域会变为from区域,经过多次的monorGC都是可用的对象,我们会将该对象转译到老年代,也就是我们使用比较多的一直不能销毁的对象,当老年代满时候,这时,这时,这时会触发fullGC,这时会停止所有的服务,全力的来处理fullGC,这时我们的程序是不可能的,所以我们要减少我们的fullGC次数。又半夜了,下篇博客我们来说说,再来说说堆里面具体是用什么样的算法来清理垃圾的。同时也会简单的说一下,我们如何可以避免我们的fullGC。

猜你喜欢

转载自www.cnblogs.com/cxiaocai/p/11502925.html