• JVM内部结构图及各模块运行机制总结


    1.JVM内部模型图

    JVM执行流程:

    利用前端编译器(javac)将.java文件编译为.class文件(字节码文件),然后通过类加载子系统将.class文件加载到运行时数据区,之后通过执行引擎对.class文件进行解释执行。

    2 类加载子系统

    类加载子系统有七个操作:加载、链接(验证、准备、解析)、初始化、使用、卸载

    2.1 加载

    把.class文件读取到运行时数据区中,详细步骤为:

    (1)通过全限定名读取到该类的二进制流(即,.class文件);

    (2)将该二进制流的静态结构读取到运行时数据区中的方法区中;

    (3)在堆中创建该类的实例对象。

    注意:加载时采用的是双亲委派机制,其原理如下图所示,当某个类加载器收到类加载请求时,会自底向上将此请求委派给其父类加载器,若最顶层的启动类加载器(Bootstrap ClassLoader)不能加载此类,则自上而下把请求交还给其子类加载器,途中有类加载器可以加载此类,则进行加载,否则一直往下传递。若到达最底层的自定义类加载器(若没有自定义类加载器,则就是应用程序类加载器(Application ClassLoader))仍无法加载此类,则报出异常。

    2.2 链接

    2.2.1 验证

    验证字节码文件是否符合JVM规范,比如字节码文件的文件开头是“CA FE BA BE”(称为魔数),这标识了它是JVM的字节码文件。

    2.2.2 准备

    为静态变量(static修饰)分配内存并赋初始值。

    2.2.3 解析

    将常量池中的符号引用(如#1,#2可能代表某个类,某个方法的符号引用)变为直接引用(内存地址)。

    2.3 初始化

    将静态变量的赋值动作以及静态代码块(static{})发生的操作整合为clinit方法进行执行。其实就是为静态变量进行真正意义上的赋值。

    2.4 使用

    2.5 卸载

    3 运行时数据区

    3.1线程私有区域

    Java虚拟机栈:

    保存局部变量表操作数栈动态链接方法出口;每个线程单独拥有一个,用于执行程序;栈中的以栈帧为一个单位,一个栈帧相当于一个方法;执行流程:当调用main方法时,会将main方法作为一个栈帧压入到栈顶,若在执行main方法时调用了其它方法,则会把其它方法也作为栈帧压入栈顶,当栈顶方法执行完毕就会弹出栈。若所有栈帧都弹出,则程序运行结束。

    本地方法栈:

    本地方法栈与Java虚拟机栈类似,但它是为了执行本地方法(Native Methods)。本地方法栈执行时,需要调用到本地方法接口(也叫JNI/Java Native Interface),而本地方法接口需要调用本地方法库。

    程序计数器:

    控制程序指令的执行顺序,程序该怎么执行,哪个方法先执行,哪个方法后执行。

    3.2 线程共享区域

    方法区:

    保存类的信息、常量池、方法数据、方法代码、JIT代码缓存等等;方法区是一种逻辑上的概念(即,JVM规范),在JDK1.7及之前方法区的落地实现叫做永久代(PermGen space),它位于堆中。在JDK1.8永久代被移除,将其变为元空间(Metaspace)。元空间与永久代最大区别在于,元空间使用的是直接内存(本地内存),而永久代使用的是堆内存。

    Java堆:

    保存new出来的实例对象

    JDK1.6时字符串常量池在运行时常量池内,属于运行时常量池的一部分;

    JDK1.6到JDK1.7的变化是把静态常量和字符串常量从方法区中移到了堆中;

    JDK1.7到JDK1.8的变化是对方法区的实现由永久代变为了元空间。

    即字符串常量池在JDK1.7之后就移到了堆中,且存储的是字符串对象的引用,而不是对象本身。

    在JDK1.8版本中,Java堆划分为新生代(NewGen)和老生代(OldGen)。

    新生代:

    1. 新生代由伊甸区(Eden space)、幸存from区(Survival from)、幸存to区(Survival to)构成。
    2. 新生代发生的GC是轻GC(Minor GC),使用的GC算法是复制算法,复制算法原理是:当触发Minor GC时,利用可达性分析算法将Eden区存活对象移到Survival to区域,同时也将Survival from区域的存活对象也移到Survival to区域,然后将Survival to区域存活对象都复制到Survival from区域,且清除那些失效对象。即,每次GC都是将存活对象存入到Survival to区域,然后将Survival from区域和Survival to区域调换位置(实际是对象的复制过程)来保证Survival to区域是空的。
    3. 复制算法适合存活周期较短的对象的垃圾回收,其优点是算法复杂度低,执行效率快,但内存空间浪费较大。

    老生代:

    1. 老生代发生的是重GC(Full GC),使用的是标记清除标记整理算法的混合版,当内存碎片产生较少时,使用标记清除算法。较多时,使用标记整理算法。
    2. 标记清楚算法:利用可达性分析算法标记存活对象(可达对象),然后统一删除不可达对象。共两次操作,执行效率较低,且可能会产生较多内存碎片,相比复制算法,内存浪费较少。
    3. 标记整理算法:利用可达性分析算法标记存活对象(可达对象),然后将它们移至一端,删除端以外的不可达对象。这样就可用保证内存的连续性,不会有内存碎片,内存使用率大幅提高,但是执行效率更低。

    4 执行引擎

    执行引擎由解释器、JIT编译器、垃圾回收器组成。

    解释器:

    用于程序代码的解释执行。

    JIT编译器:

    用于将热点代码(重复执行次数较多的代码)提前编译,存储在方法区中,以便下次使用。这是为了程序执行的效率考虑。

    垃圾回收器:

    新生代垃圾回收器:Serial、ParNew、Parallel Scavenge

    老生代垃圾回收器:Serial Old、Parallel Old、CMS

  • 相关阅读:
    【动态规划】198. 打家劫舍、213. 打家劫舍 II、337. 打家劫舍 III
    【MySQL篇】第三篇——表的操作
    开源|用 Java 实现一个生成 Markdown 文本的工具
    【Java八股文总结】之Spring MVC
    Docker镜像分层
    火车头图片储存-火车头采集图片储存插件及教程
    手机号码携号转网查询保障用户权益、信息透明、优化用户体验
    为什么说CDN是网站速度优化大师
    【Terraform】Terraform自动创建云服务器脚本
    Eureka高可用集群服务端和客户端配置
  • 原文地址:https://blog.csdn.net/qq_36134376/article/details/126106450