JVM JRE JDK

JVM JRE JDK

一、 基本概念

JDK(Java Development Kit)

  • JDK是Java Development Kit,它是功能⻬全的Java SDK。它拥有JRE所拥有的⼀切,还有编译器(javac)和⼯具(如javadoc和jdb)。它能够创建和编译程序。
  • tips:SDK(Software Development Kit)软件开发工具包

JRE(Java Runtime Enviroment)

  • JRE是Java运⾏时环境。它是运⾏已编译Java程序所需的所有内容的集合,包括Java虚拟机
    (JVM),Java类库,java命令和其他的⼀些基础构件。但是,它不能⽤于创建新程序。

JVM(Java Virtual Marchine)

  • JVM是运⾏Java字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOS),⽬的是使⽤相同的字节码,它们都会给出相同的结果。字节码和不同系统的JVM实现是Java语⾔“⼀次编译,随处可以运⾏”的关键所在。
什么是字节码?采⽤字节码的好处是什么?
  • 在 Java中,JVM可以理解的代码就叫做字节码(即扩展名为.class的⽂件),它不⾯向任何特定的处理器,只⾯向虚拟机。
  • Java 语⾔通过字节码的⽅式,在⼀定程度上解决了传统解释型语⾔执⾏效率低的问题,同时⼜保留了解释型语⾔可移植的特点。所以Java程序运⾏时⽐较⾼效,⽽且,由于字节码并不针对⼀种特定的机器,因此,Java程序⽆须重新编译便可在多种不同操作系统的计算机上运⾏。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wj8FGZLS-1640111411552)(D:\CYL\Notes\JAVA\IMG\JVM JRE JDK 01.png)]
在这里插入图片描述
在这里插入图片描述

二、JVM

  • JVM是可运行Java代码的假想计算机,包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收,堆和一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接的交互。

运行

Java程序从源代码到运行一般有下面3步:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fpW6nHoj-1640111411556)(D:\CYL\Notes\JAVA\IMG\JAVA编译运行过程01.png)]

  • 我们都知道Java源文件,通过编译器,能够生产相应的.Class文件,也就是字节码文件,而字节码文件又通过Java虚拟机中的解释器,编译成特定机器上的机器码。
    也就是如下:

1. Java 源文件—>编译器—>字节码文件
2. 字节码文件—>JVM—>机器码

具体(Java代码的执行)
  1)代码编译为class —> javac
  2)装载class -----> ClassLoader
  3)执行class
    (1) 解释程序
    (2) 编译程序
      client compiler
      sever compiler
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MAab3DN3-1640111411557)(D:\CYL\Notes\JAVA\IMG\JAVA编译运行过程03.png)]

我们需要格外注意的是.class->机器码这⼀步。
   在这⼀步JVM类加载器首先加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度会相对比较慢。而且,有些方法和代码块是经常需要被调用的(也就是所谓的热点代码),所以后面引进了JIT编译器,而JIT属于运行时编译。当JIT编译器完成第⼀次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。而我们知道,机器码的运行效率肯定是高于Java解释器的。这也解释了我们为什么经常会说Java是编译与解释共存的语言。

  HotSpot采⽤了惰性评估(Lazy Evaluation)的做法,根据二八定律,消耗⼤部分系统资源的只有那⼀⼩部分的代码(热点代码),⽽这也就是JIT所需要编译的部分。JVM会根据代码每次被执⾏的情况收集信息并相应地做出⼀些优化,因此执⾏的次数越多,它的速度就越快。
  JDK9引⼊了⼀种新的编译模式AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了JIT预热等各⽅⾯的开销。JDK ⽀持分层编译和AOT协作使⽤。但是,AOT编译器的编译质量是肯定⽐不上JIT编译器的。

  每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这也就是Java为什么能够跨平台的原因了,当一个程序从开始运行,这时虚拟机就开始实例化了,多个程序启动就会存在多个虚拟机实例。程序退出或者关闭,则虚拟机实例消亡,多个虚拟机实例之间数据不能共享。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QU12ZH9E-1640111411558)(D:\CYL\Notes\JAVA\IMG\JAVA编译运行过程02.png)]

1.1 线程

  这里所说的线程指程序执行过程中的一个线程实体。JVM允许一个应用并发执行多个线程。Hotspot JVM中的 Java线程与原生操作系统线程有直接的映射关系。当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程。Java线程结束,原生线程随之被回收。操作系统负责调度所有线程,并把它们分配到任何可用的CPU上。当原生线程初始化完毕,就会调用Java线程的run()方法。当线程结束时,会释放原生线程和Java线程的所有资源。

Hotspot JVM 后台运行的(系统线程)主要有下面几个:
1.虚拟机线程(VM thread)

  这个线程等待JVM到达安全点操作出现。这些操作必须要在独立的线程里执行,因为当堆修改无法进行时,线程都需要JVM位于安全点。这些操作的类型有:stop-the-world垃圾回收、线程栈dump、线程暂停、线程偏向锁(biased locking)解除。

2.周期性任务线程

  这线程负责定时器事件(也就是中断),用来调度周期性操作的执行。

3.GC线程

  这些线程支持 JVM 中不同的垃圾回收活动。

4.编译器线程

  这些线程在运行时将字节码动态编译成本地平台相关的机器码。

5.信号分发线程

  这个线程接收发送到 JVM 的信号并调用适当的 JVM 方法处理。

1.2 JVM内存区域

JVM内存区域主要分为
1.线程私有区域(程序计数器、虚拟机栈、本地方法区)

  线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束而创建/销毁(在 Hotspot VM内, 每个线程都与操作系统的本地线程直接映射, 因此这部分内存区域的存/否跟随本地线程的生/死对应)。

2.线程共享区域(JAVA堆、方法区)

  线程共享区域随虚拟机的启动/关闭而创建/销毁。

3.直接内存。

  直接内存并不是JVM运行时数据区的一部分,但也会被频繁的使用:在JDK1.4引入的NIO提供了基于 Channel与Buffer的IO方式,它可以使用 Native 函数库直接分配堆外内存,然后使用DirectByteBuffer 对象作为这块内存的引用进行操作(详见:JavaI/O扩展),这样就避免了在Java堆和 Native堆中来回复制数据, 因此在一些场景中可以显著提高性能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ur2VguEc-1640111411559)(D:\CYL\Notes\JAVA\IMG\JDK1.8内存区域.png)]

在这里插入图片描述

1.2.1 程序计数器(线程私有)

   一块较小的内存空间, 是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程私有”的内存。正在执行 java 方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果还是 Native 方法,则为空。
  这个内存区域是唯一一个在虚拟机中没有规定任何 OutOfMemoryError 情况的区域。

1.2.2 虚拟机栈(线程私有)

是描述java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。栈帧(Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)、 方法返回值异常分派( Dispatch Exception)。栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。
在这里插入图片描述

1.2.3 本地方法区(线程私有)

本地方法区和Java Stack作用类似, 区别是虚拟机栈为执行Java方法服务, 而本地方法栈则为Native方法服务,如果一个VM实现使用C-linkage模型来支持Native调用, 那么该栈将会是一个C栈,但HotSpot VM直接就把本地方法栈和虚拟机栈合二为一。

1.2.4 堆(Heap-线程共享)-运行时数据区

是被线程共享的一块内存区域,创建的对象和数组都保存在 Java 堆内存中也是垃圾收集器进行垃圾收集的最重要的内存区域。由于现代VM采用分代收集算法, 因此Java堆从GC的角度还可以细分为: 新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代。

1.2.5 方法区/永久代(线程共享)

即我们常说的永久代(Permanent Generation), 用于存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。HotSpot VM把GC分代收集扩展至方法区, 即使用Java堆的永久代来实现方法区, 这样 HotSpot的垃圾收集器就可以像管理 Java 堆一样管理这部分内存, 而不必为方法区开发专门的内存管理器(永久带的内存回收的主要目标是针对常量池的回收和类型的卸载, 因此收益一般很小)。
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。 Java 虚拟机对 Class 文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值