JDK
JDK内部体系结构:
整个jdk内部体系结构,大体可分为两部分:命令工具和JRE。
- jdk自带了一些命令工具。比如java、javac、javap 和 jar命令等
javac:用于将java源代码编译成字节码文件,也就是 通过Java的编译器(Windows下的javac.exe),对源文件进行错误排查后,形成后缀名为**.class**的字节码文件。
字节码文件:是一种与任何具体的"机器环境" 和 “操作系统环境” 无关的中间代码,同时也是一个二进制文件。
java:用于让JVM执行字节码文件。
- JRE(Java运行时环境):包括 类库 和 JVM。
(1) 支撑Java程序运行的核心类库。比如I/O,网络(NetWorking),并发(Concurrency),lang 和 util包等。
(2) Java虚拟机JVM(Java Virtual Machine)
JVM 与 跨平台
Java最大的特性跨平台,就是由JVM帮我们实现的。
- JVM 从软件层面 屏蔽了 不同操作系统 在底层 硬件 与 指令 上的区别。也就是,JVM兼容了不同的操作系统,因为我们在下载jdk的时候,下载了不同的基于这个操作系统 特定的jdk版本,它里面就有 针对 特定平台的JVM。
- 实际上,计算机底层只认识0101的二进制机器码,但是由于不同操作系统 不同硬件平台上 指令集 的区别,同一份代码的功能实现,在不同操作系统底层 对应的二进制机器码 是不一样的,而JVM可以生成 基于这个操作系统 特定的 机器可执行的 二进制机器码。比如,一个加法功能的实现,在Windows上生成的是010101,而在 Linux上生成的 可能是110001…。
- 如果我选择了 基于Windows版本的jdk,那它对应给我们运行代码的JVM,就是基于这个Windows操作系统,做了一些特定的实现。然后,我们写了一份java源代码,比如Helloword.java。然后通过javac指令编译成Helloword.class字节码文件,再通过java指令(java Helloword.class),将字节码文件丢到JVM里去运行。需要注意的是,我们只写了一份代码,生成了一份字节码(没有平台限制),最终由 JVM 生成基于这个操作系统 特定的 可执行的二进制机器码。
- 因为 Java是先编译成**.class**字节码文件,然后再利用JVM进行解释执行的,是一种在编译基础上进行解释运行的语言。所以,Java即可以说成编译型,也可以说成解释型语言。
- 简而言之,跨平台就是,代码一次编写,到处运行。开发人员 只需写一份代码,最终可以放到各大平台去运行,比如Windows,Linux,Unix 和 Mac等。
JVM在程序运行过程中的运行细节,内存分配 和 流转模型。
JVM结构体系
- 一个完整的JVM结构体系 由3部分组成:类装载子系统、运行时数据区 和 字节码执行引擎。他们的作用和联系,也就是字节码文件在JVM中的 执行过程 与 运行原理。
- 当我们用java指令 去运行一个字节码文件时(比如java Math.class),JVM就开始运行了。字节码文件会首先通过JVM的第一块区域 类装载子系统,它会把我们的字节码文件装载(load)到JVM的第二块区域 运行时数据区(也叫内存模型/内存区域),最终,由我们JVM的第三块区域 字节码执行引擎,来执行我们内存里面的一行一行的代码。
- 在整个JVM的组成中,最为重要的部分,其实就是内存区域,JVM调优实际上调的就是这个区域的相关部分,而其中的堆内存是最为主要的调优部分。
- 内存区域 在 oracle官方文档的JVM规范 里面,有一些详细的定义和介绍,
- 内存区域在规范里面的官方名称,叫做运行时数据区(Run-Time Data Areas),它的内部又包含5个部分:
- 第一部分是程序计数器(The pc Register),
- 第二部分是Java虚拟机栈(Java Virtual Machine Stacks),
- 第三部分是堆(heap),
- 第four部分是方法区(Method Area),方法区中又包括常量池(Run-Time Constant Pool),
- 第五部分是本地方法栈(Native Method Stacks),
- 这些部分都属于JVM的内存区域,是用来存储数据的,但它们的作用和存储的内容各不相同。
1. 虚拟机栈
- 虚拟机栈 这块区域主要是用来 存放 我们的线程运行过程中,它的那些局部变量,比如在我们java代码中,(包括main方法在内)每一个方法,都有属于自己的局部变量。这些变量就是存放在我们的"栈"内存区域。
2. 线程栈
- 因为 Java虚拟机中的 每个线程 都有一个私有的虚拟机栈,与线程同一时间被创建出来。也就是说,在我们的java代码中,只要有一个线程开始运行代码了,JVM就会马上给这个线程,在整个一大块虚拟机栈的内存区域中,分配一小块属于这个线程 自己独立的内存空间,用来存放 我们这个线程(自己运行过程中)内部 的局部变量。所以对于线程而言,每个线程 自己私有的虚拟机栈 也可以更形象的称之为线程栈。