精选文章 一张图读懂JVM

一张图读懂JVM

作者:SimminonGarcia 时间: 2018-05-06 09:28:00
SimminonGarcia 2018-05-06 09:28:00

     每一个Java 开发者都知道字节码是通过JRE(Java 运行时环境)执行的,JRE实现了JVM ,JVM可以解析执行字节码文件。

     什么是JVM?

     虚拟机是一个软件,它是物理机的实现。Java 开发是建立在一次编译到处运行(Write Once Run Anywhere)的理念上的。Java编译器首先编译Java代码为.class文件。Class文件加载进入JVM,进行解析执行。

JVM体系结构图:

一张图读懂JVM2

 

JVM 如何工作(本文主要针对主流HotSpot虚拟机)?如上图所示 JVM 主要分割成为了3个主要的系统:

  • 类加载系统
  • 运行时数据区
  • 执行引擎

1.类加载系统( Class Loader System)

     类加载器把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。与那些在编译时期需要进行连接工作的语言不同,Java语言中类的加载在程序运行时完成的。以下为类加载的主要过程:

1.1 加载,类加载器主要有以下三种:

        启动类加载器:Bootstrap ClassLoader,跟上面相同。它负责加载存放在JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被Bootstrap ClassLoader加载)。启动类加载器是无法被Java程序直接引用的。

        扩展类加载器:Extension ClassLoader,该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载JDK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。

        应用程序类加载器:Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

当加载class 文件时,以上类加载器会遵循双亲委派模型.如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载.参见classLoader加载类的loadClass方法

 protected Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        // 首先委托给父类去加载
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // z自行加载
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

1.2 连接

     验证 -  验证的目的是为了确保Class文件中的字节流包含的信息符合当前虚拟机的要求,而且不会危害虚拟机自身的安全。

     准备 - 准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。

     解析 - 解析阶段是虚拟机将常量池中的符号引用转化为直接引用的过程;

1.3 初始化

     初始化是类加载过程的最后一步,到了此阶段,才真正开始执行类中定义的Java程序代码。在准备阶段,类变量已经被赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员通过程序指定的主观计划去初始化类变量和其他资源。

2.运行时数据区,运行时数据区主要分为下面5个区域:

  1. 方法区(Method Area) – 方法区是各个线程共享的内存区域,它用于存储已经被虚拟机加载的类信息、常量、静态变量、即编译器编译后的代码等数据.这个区域会抛出 OutOfMemory异常;运行时常量池是方法区的一部分。Class 文件除了类的版本、字段、方法、接口等描述信息外,还有一项是常量池,用于存放编译期生成的各种字面量和符号引用。
  2. 堆(Heap Area) – 堆也是各个线程共享得到内存区域,非线程安全。在虚拟机启动时建立,主要用于存储对象实例。由于现在的垃圾收集器都采用分代收集算法,堆可以分为新生代和老年代;
  3. 栈(Stack Area) – 虚拟机栈是线程私有的, 它的生命周期与线程相同。 每个方法执行时,虚拟机都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接以及方法出口等信息。局部变量表存放了编译期可知的各种基本数据类型和对象引用(reference类型,它是一个指向对象起始位置的引用指针,或者指向代表对象句柄的位置。这个区域会抛出 StackOverflowError和 OutOfMemory异常)
  4. 程序计数器(Program Counter Registers) – 当前线程所执行的字节码行号的行号指示器,每个线程私有。Java 虚拟机的多线程是通过线程轮流切换并分配处理器的执行时间的方式实现的。任何一个确定的时刻,一个处理器只会执行一个线程中的指令。为了线程切换后能恢复到正确的执行位置,每个线程都需要一个线程计数器记录虚拟机字节码指令地址。
  5. 本地方法区(Native Method stacks) – 本地方法区与栈类似,只不过本地方法区执行的是虚拟机Native方法。

3. 执行引擎

字节码加载进运行时数据区(Runtime Data Area )后,会被执行引擎执行。执行引擎主要分为以下几个组件:

  • 解析器(Interpreter) – 解析器解析字节码很快,但是执行很慢。它的劣势是,当一个方法被调用多次时,每次都需要创建一个新的解析器。
  • JIT 编译器– 当遇到相同的代码时, JIT 编译器会把相同的字节码为本地方法。
  • 垃圾收集器(Garbage Collector)

转载于:https://my.oschina.net/freedemon/blog/1807879

勿删,copyright占位
分享文章到微博
分享文章到朋友圈

上一篇:HTML布局四剑客-Flex,Grid,Table,Float

下一篇:Spring Cloud Config对特殊字符加密的处理

您可能感兴趣

  • 计算机必备专用英语词汇

    非常好的单词整理,转载一下当作笔记 1.单词说明:   command n. 命令,指令 [kə'mɑ:nd]   单词拼写 名词 单词含义 音标(发音)   提示:着重记忆单词对应的意思,有能力最好词性也记忆。 2.词性说明: n v vi vt conj prep pron adj adv 名词 动词 非及物动词 及物动词 连词 介词 代词 形容词 副词 3.单词列表: 1.file,n...

  • Java Lambda表达式

    点击上方“java大数据修炼之道”,选择“置顶或者星标” 你想要的优质技术好文第一时间送达! 来源 | http://tutorials.jenkov.com/java/lambda-expressions.html Java Lambda表达式是Java8中的新特性。Java lambda表达式是Java进入函数式编程的第一步。因此,Java lambda表达式是可以单独创建的函数,而无需...

  • 图解一致性哈希算法,全网(小区局域网)最通俗易懂

    好久不见小伙伴们,最近都快忙晕了,后端技术学堂差点停课,不过还是抽时间写了这篇文章带大家一起学习一致性哈希算法。 很多同学应该都知道什么是哈希函数,在后端面试和开发中会遇到「一致性哈希」,那么什么是一致性哈希呢?名字听起来很厉害的样子,其实原理并不复杂,这篇文章带你彻底搞懂一致性哈希! 进入主题前,先来一场紧张刺激的模拟面试吧。 模拟面试 面试官:看你简历上写参与了一个大型项目,用到了分布式...

  • MySQL:互联网公司常用分库分表方案汇总

    点击上方 IT牧场 ,选择 置顶或者星标 技术干货每日送达! 作者:尜尜人物 cnblogs.com/littlecharacter/p/9342129.html 本文目录 一、数据库瓶颈 IO瓶颈 CPU瓶颈 二、分库分表 水平分库 水平分表 垂直分库 垂直分表 三、分库分表工具 四、分库分表步骤 五、分库分表问题 非partition key的查询问题 非partition key跨库跨...

  • JAVA面试(全)

    Java 八大基本数据类型 八大基本类型 Byte,short,long,int,double,float,boolean,char 占用大小及其长度 数据类型 空间(字节B) 取值范围 byte 1 -2^7 ~ 2^7-1 short 2 -2^15~ 2^15-1 char 2 0 ~ 2^16-1 char无需符号位 int 4 -2^31 ~ 2^31-1 float 4 -2^3...

  • OpenGL学习笔记9-Camera

    Camera Getting-started/Camera 在前一章中,我们讨论了视图矩阵以及如何使用视图矩阵在场景中移动(我们稍微向后移动了一点)。OpenGL本身并不熟悉相机的概念,但我们可以通过逆向移动场景中的所有对象来模拟相机,给人一种我们正在移动的错觉 在本章中,我们将讨论如何在OpenGL中设置一个摄像头。我们将讨论一个飞行风格的相机,允许你在一个3D场景中自由移动。我们还将讨论...

  • 《重新定义公司》读书笔记

    激励偏向的是事成之后的利益分享,而赋能强调的,是激起创意人的兴趣与动力,给予挑战。唯有发自内心的志趣,才能激发持续的创造,命令则不适用于他们。因此,组织的职能不再是分派任务和监工,而更多的是让员工的专长、兴趣和客户的问题有更好的匹配,这往往要求更多的员工自主性、更高的流动性和更灵活的组织。我们甚至可以说,是员工使用了组织的公共服务,而不是公司雇用了员工。两者的根本关系发生了颠倒。 年少时,第...

  • Flink 1.11 SQL 使用攻略

    7 月 6 日,Apache Flink 1.11 正式发布。从 3 月初进行功能规划到 7 月初正式发版,1.11 用将近 4 个月的时间重点优化了 Flink 的易用性问题,提升用户的生产使用体验。 SQL 作为 Flink 中公认的核心模块之一,对推动 Flink 流批一体功能的完善至关重要。在 1.11 中,Flink SQL 也进行了大量的增强与完善,开发大功能 10 余项,不仅扩...

华为云40多款云服务产品0元试用活动

免费套餐,马上领取!
CSDN

CSDN

中国开发者社区CSDN (Chinese Software Developer Network) 创立于1999年,致力为中国开发者提供知识传播、在线学习、职业发展等全生命周期服务。