java语言基础

一. jdk/jre/jvm/jit关系图

二. java基本概念

Java类加载器(Java Classloader): 是Java运行时环境(JRE)的一部分, 负责动态加载Java类到JVM的内存空间中
JVM:一种能够运行Java字节码(Java bytecode)的虚拟机。
字节码:字节码是已经经过编译,但与特定机器码无关,需要解释器转译后才能成为机器码的中间代码。
Java字节码:是Java虚拟机执行的一种指令格式。
解释器:是一种计算机程序,能够把高级编程语言一行一行直接翻译运行。
即时编译(Just-in-time compilation: JIT):又叫实时编译、及时编译。是指一种在运行时期把字节码编译成原生机器码的技术,一句一句翻译源代码,但是会将翻译过的代码缓存起来以降低性能耗损。这项技术是被用来改善虚拟机的性能的。
JIT编译器是JRE的一部分。原本的Java程序都是要经过解释执行的,其执行速度肯定比可执行的二进制字节码程序慢。为了提高执行速度,引入了JIT。在运行时,JIT会把翻译过来的机器码保存起来,以备下次使用。而如果JIT对每条字节码都进行编译,则会负担过重,所以,JIT只会对经常执行的字节码进行编译,如循环,高频度使用的方法等。它会以整个方法为单位,一次性将整个方法的字节码编译为本地机器码,然后直接运行编译后的机器码。
运行时类: 加载到内存中的字节码文件对应的类称为运行时类,  此运行时类即为一个Class的实例。

三. java 运行过程。

java的特点是:一次编译,到处运行。

编译:java源文件(.java)---java编译器(javac)--->字节码文件(.class)--JVM-->机器码(运行)
载入:java虚拟机(JVM)通过类加载器(ClassLoader)将字节码加载进内存。
翻译:JVM中的java解释器(java)将字节码翻译成对应平台(OS+硬件)的机器码供运行。

当程序要使用某个类时, 如果该类还未被加载到内存中, 则系统会通过加载, 连接, 初始化三步来实现对这个类进行初始化:


(1)加载就是将class文件读入内存, 并为之创建一个Class对象(任何类被使用时系统都会创建且只创建一个Class对象)

类加载的三步骤
1. 通过类的全限定名称来获取类的二进制字节流
2. 将字节流所蕴含的静态存储结构转化为方法区运行时数据结构
3. 在java堆中生成一个代表这个类的java.lang.Class对象, 作为方法区数据的访问入口
类的加载的最终产品是Class对象(堆区), Class对象封装了类在方法区内的数据结构, 提供了访问这些数据结构的接口。
类的加载时机:通俗的说就是只要用到了类的东西类就会加载。
JVM在运行时会产生3个类加载器组成的初始化加载器层次结构:
Bootstrap ClassLoader 根类加载器,负责java核心类的加载,比如System, String等, 在JDK中JRE的lib目录下rt的jar文件中
Extension ClassLoader (JRE)扩展类加载器,负责JRE的扩展目录中jar包的加载 jre/lib/ext目录下的jar包。
System ClassLoader 系统类加载器,加载自己写的类以及第三方类库(导入的jar包)。

(2)连接就是将类的二进制数据合并到JRE

连接就是将类的二进制数据合并到JRE中 ,连接分为以下三步:
(1)验证,检查载入Class文件数据的正确性
(2)准备,该阶段正式为类变量分配内存并设置类变量初始值。
注意:1.这些变量所使用的内存将在方法区中进行分配, 此时进行内存分配的仅包括类变量, 而不包括实例变量(实例变量将会在对象实例化时随着对象一起分配在Java堆中)。
   2.在这里分配的静态类变量是将其值定义为默认值, 这里所设置的初始值通常情况下是数据类型默认的零值(如0, 0L, null, false等), 而不是被在Java代码中被显式地赋予的值, 正确的赋值将在初始化阶段执行。
(3)解析,将类的二进制数据中的符号引用替换为直接引用
比如将运算中符号a=1 去掉a直接变成1

(3)初始化就是对类的静态变量, 静态代码块执行初始化操作。
到了初始化阶段, 才真正开始执行类中定义的Java程序代码,JVM负责对类的静态变量赋予正确的初始值, 在Java中对类变量进行初始值设定有两种方式:1.声明静态变量(类变量)时指定初始值2.使用静态代码块为类变量指定初始值。
初始化步骤:
1. 假如这个类还没有被加载和连接, 则程序先加载并连接该类。
2. 假如该类的直接父类还没有被初始化, 则先初始化其直接父类。
3. 假如类中有初始化语句, 则系统依次执行这些初始化语句。


JVM在堆内存中创建对象, 类的成员变量进入到堆内存中, 赋默认值。最后就是我们熟悉的Runtime运行时阶段。

Person p = new Person();
p.study();

执行上述代码会在堆内存创建一个Person类的对象, 并且在栈内存分配一块储存空间存放Person类型的引用变量p, p存放该对象的地址并且指向该对象, 调用p的study方法实际是, 对象通过Person类的字节码对象来访问方法区Person字节码的study方法。

四. JVM的内存模型

原文地址:https://www.cnblogs.com/shijianchuzhenzhi/p/12889210.html