1. 关于JVM
JVM(Java Virtual Machine),是Java语言两大最鲜明的特点之一(另一个为垃圾回收机制GC),JVM是Java能够自由在Linux、Windows、Unix等操作系统上无差别编译执行的前提,其屏蔽了不同操作系统在底层指令和硬件的不同之处,大大提高了Java程序的可移植性。Java程序员只需要学习并使用Java进行业务程序开发,而不必学习每个操作系统的细节与不同之处,减少了不必要的学习压力与时间。
2. JVM的内存结构
2.1 类加载系统
类加载系统可以看做是一个勤劳的“快递员”,当我们运行一个Java程序时,可以分为两个过程:编译和运行。编译过程通过javac命令将我们写的.java文件编译为.class字节码文件,执行时调用java.exe命令,类加载系统就会将该.class字节码文件加载进JVM,并执行一系列操作{加载(Loading) --- 验证(Verification) --- 准备(preparation) --- 解析(Resolution)} --- 初始化(Initialization)},在JVM方法区中生成一个java.lang.Class对象,做为这个类的各种数据访问入口
2.1.1 类加载器
JVM自带的加载器:
- 启动类加载器(Bootstrap) C++编写,自动加载JAVA自带的初始class字节码文件(存放路径:$JAVA_HOME/jre/lib/rt.jar),如Object.class 、String.class等 --
- 扩展性加载器(Extension) JAVA编写,自动加载JAVA版本迭代更新中新产生的扩展包(存放路径:$JAVA_HOME/jre/lib/ext/*.jar)
- 应用程序类加载器(AppClassLoader),也叫系统类加载器,加载当前应用的classpath的所有类,即用户自定义的业务类
用户自定义加载器:
用户可以自定义类继承Java.lang.ClassLoader的子类,定制类的加载器
2.1.2 类加载的过程
- 加载(Loading):通过字节流方式获取.class字节码文件,这个阶段就会生成该类所对应的Java.lang.Class对象(仅仅是生成,相当于只是一个架构)
- 验证(Verification):验证字节码文件的格式是否符合当前JVM要求(经典的“cafe babe”开头 ^_^)
- 准备(preparation):为该类的静态变量分配内存并赋值默认值(如int=0,String=null等)
- 解析(Resolution):可以理解为处理该类中引用关系(如当前类中引用了其他类,则这一步会形成指针指向关系),这一步骤也可能在初始化后执行
- 初始化(Initialization):执行类构造器<clinit>()方法,注意该构造器方法不是实例化类时的构造方法,执行该方法初始化类的静态变量,即真正赋值
2.1.3 双亲委派
类加载器的层次结构
对于JAVA程序中类的加载,首先通过启动类加载器加载,如果没有找到该类便从扩展性加载器尝试加载,还没有才从应用程序类加载器加载,即类的加载过程总是先找父类加载器,父类无法加载才找子类加载器。如用户自定义一个类命名为String,并设置main方法,但运行会抛出无法找到main方法异常,因为运行时加载到JVM中的不是用户自定义的String,而是rt.jar中的String(JAVA 源代码)**
双亲委派机制能够有效防止JAVA源代码被恶意污染,也加强了JAVA的稳定性,即沙盒安全
2.2 运行时数据区
JVM的运行时数据区主要包括五大部分:
堆(Heap):JVM主要的数据存储地点,JVM中几乎所有的运行时对象都在堆区存放,其中堆区又可以细分为:Eden区、Survivor区和Old区,这种划分是为了实现分代垃圾回收机制
栈(Stack):每条线程实际的工作空间。JVM会给每条线程分配一个独立的栈空间,线程的任务执行都在该空间内执行
本地方法栈(Native Method Stack): 在JVM为每条线程分配栈空间时,也会分配一个本地方法栈,线程中如果调用了本地方法(C/C++程序),会在本地方法栈中压栈执行
方法区(Method Area):逻辑上的一个概念,存储着每一个类的结构信息(Class对象)、常量池、字段和方法数据、构造方法和普通方法的字节码内容。方法区在不同JVM版本中有不同的实现,最经典的就是1.7(PermGen space)的永久代和1.8的元空间(Metaspace)
程序计数器(也叫PC寄存器):维护一个指针变量,记录当前线程下一条字节码指令的地址,如果当前进程丢失CPU执行权,可通过该机制记录程序执行的断点,在重新获得CPU执行权后可以定位到上次执行的断点处并往下执行。如果执行的是本地方法,则寄存器不会进行变动。
运行时数据区小总结:
- 堆区和方法区为线程共享
- 栈、本地方法区和PC寄存器为线程私有,JVM会为每条线程分发一套
- 栈由一个个栈帧组成,每个栈帧相当于线程调用的每一个方法,压栈执行,执行完后出栈并释放内存,其中main方法默认总是在栈底
2.3 执行引擎
负责解释字节码文件命令,提交操作系统执行
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。