JVM内存模型剖析

要想对jvm内存模型有深度的了解,要先了解jvm虚拟机是由哪几部分组成的,每一部分的作用是什么。以下是对jdk8进行说明。

jvm虚拟机的组成:类装载子系统、字节码执行引擎、运行时数据区(内存模型)。

我们常说的堆、栈等都是属于运行时数据区内部的,先看下图,再进行详细的讲解

接下来,我们写一个简单的java程序,用这个java程序来执行过程来很好地说明每一块内容所做的内容。

public class Demo {

    public static void main(String[] args) {
        Demo math = new Demo();
        math.compute();

    }

    public int compute(){
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }
}

该代码运行后,首先会通过类装载子系统加载(C++实现),将字节码放到运行时数据区,由字节码执行引擎(C++实现)执行代码。其中最核心的就是运行时数据区,其中jvm调优主要也是针对该部分区域。

运行时数据区主要有五个部分,栈、方法区、本地方法栈、程序计数器、 堆。

当我们的代码主方法运行,会在栈上分配出一块空间,供给主方法使用。当有多个用户(主方法)运行时,栈会开辟出多块区域,每一块区域运行一个主方法。类似于多线程运行。

main()方法运行后,会在栈上开辟一块区域供给代码运行,其中每个方法会在该区域内创建一个栈帧。如图

每个栈帧中又有局部变量表、操作数栈、动态连接和方法出口。

程序执行的流程就是compute()字节码文件中执行“int a = 1;”时,先把“1”压入操作数栈,然后再把“1”出操作数栈放入局部变量表中的“a”变量。(具体参见jvm指令合计)

操作数栈说白了就是程序在运行过程中临时进行中转的地方。

局部变量表就是compute()中的a、b、c变量。

动态连接就是把符号引用转变为直接引用。看到这里可能一脸懵,什么是符号引用,在我们jvm加载过程中,会把字节码放到方法区中由执行引擎执行。例如“math.compute();”这样的代码一般是由解释器(暂时理解,后续更新JIT时会讲解,里面涉及到一个阈值)逐行解析运行,这样的是符号引用。而动态链接会将“math.compute();”的符号引用转变成compute()里面的代码。动态连接比较抽象,后续涉及到对象头还会再次进行说明。

方法出口,顾名思义就是跳出方法的用途。

方法区

方法区中有很多的常量池,例如,运行时常量池、字符串常量池。主要由常量+静态变量+类信息等组成。类信息就像一些类的代码字节码这种。这部分后面后面会更新jvm优化的部分,其中GC的原因就有常量池相关的。如下图。

本地方法栈

运行过程需要调用一些本地方法,如C++等。比如“new Thread().start();”这行代码,底层调用的就是C++的.dll文件,调用这些方法也需要存储空间,这个空间就是本地方法栈。

程序计数器

每执行过一行代码,字节码执行引擎会动态的修改程序计数器的值。当切换线程时能够准确地执行,每个线程的程序计数器和本地方法栈都是独有的。

 堆

jdk8默认分为年轻代和老年代,年轻代又分为Eden区和Suvivor区。年轻代垃圾回收做minorGC,而FullGC会回收整个堆的垃圾对象。但这个过程中会产生Stop the wrold,会导致用户线程卡顿,所以我们进行jvm优化处了配置一些合理的参数外,还要根据业务情况不断地持续优化堆的参数,已达到减少FullGC。当然也不全是优化FullGC,比如JIT等也是有必要做适当的优化。

那么JVM内存模型你懂了吗?如果你有不同的见解,欢迎友好交流,我是小菜。

 

 

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值