前言:有关JVM其他的知识可以看我之前写的文章JVM相关知识

由上图可以看出,JVM的组成部分由以下四部分组成:
而JVM的运行流程如下: (1)类加载器(ClassLoader)把Java代码转换为字节码 (2)运行时数据区(Runtime Data Area)把字节码加载到内存中,而字节码文件只是JVM的一套指令集规范,并不能直接交给底层系统去执行,而是有执行引擎运行 (3)执行引擎(Execution Engine)将字节码翻译为底层系统指令,再交由CPU执行去执行,此时需要调用其他语言的本地库接口(Native Method Library)来实现整个程序的功能。
程序计数器:线程私有的,内部保存的字节码的行号。用于记录正在执行的字节码指令的地址。 java虚拟机对于多线程是通过线程轮流切换并且分配线程执行时间。在任何的一个时间点上,一个处理器只会处理执行一个线程,如果当前被执行的这个线程它所分配的执行时间用完了【挂起】。处理器会切换到另外的一个线程上来进行执行。并且这个线程的执行时间用完了,接着处理器就会又来执行被挂起的这个线程。 那么现在有一个问题就是,当前处理器如何能够知道,对于这个被挂起的线程,它上一次执行到了哪里?那么这时就需要从程序计数器中来回去到当前的这个线程他上一次执行的行号,然后接着继续向下执行。 程序计数器是JVM规范中唯一一个没有规定出现OOM的区域,所以这个空间也不会进行GC
线程共享的区域:主要用来保存对象实例,数组等,当堆中没有内存空间可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。Java8的内存结构图图下


在 HotSpot JVM 中,永久代( ≈ 方法区)中用于存放类和方法的元数据以及常量池,比如Class 和 Method。每当一个类初次被加载的时候,它的元数据都会放到永久代中。 永久代是有大小限制的,因此如果加载的类太多,很有可能导致永久代内存溢出,即OutOfMemoryError,为此不得不对虚拟机做调优。 那么,Java 8 中 PermGen 为什么被移出 HotSpot JVM 了? 官网给出了解释:JEP 122: Remove the Permanent Generation 1)由于 PermGen 内存经常会溢出,引发OutOfMemoryError,因此 JVM 的开发者希望这一块内存可以更灵活地被管理,不要再经常出现这样的 OOM。 2)移除 PermGen 可以促进 HotSpot JVM 与 JRockit VM 的融合,因为 JRockit 没有永久代。 准确来说,Perm 区中的字符串常量池被移到了堆内存中是在 Java7 之后,Java 8 时,PermGen 被元空间代替,其他内容比如类元信息、字段、静态属性、方法、常量等都移动到元空间区。比如 java/lang/Object 类元信息、静态属性 System.out、整型常量等。 元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。

1、栈内存一般会用来存储局部变量和方法调用,但堆内存是用来存储Java对象和数组的的。堆会GC垃圾回收,而栈不会。 2、栈内存是线程私有的,而堆内存是线程共有的。 3,、两者异常错误不同,但如果栈内存或者堆内存不足都会抛出异常。 栈空间不足:java.lang.StackOverFlowError。 堆空间不足:java.lang.OutOfMemoryError。
一个类的加载过程如下:

类加载器通常有四种类型:
而启动类加载器,扩展类加载器,应用程序类加载器,自定义类加载器又有以下几种关系

类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这三个部分统称为连接(linking)。


验证类是否符合JVM规范,安全性检查 (1)文件格式验证:是否符合Class文件的规范 (2)元数据验证 这个类是否有父类(除了Object这个类之外,其余的类都应该有父类) 这个类是否继承(extends)了被final修饰过的类(被final修饰过的类表示类不能被继承) 类中的字段、方法是否与父类产生矛盾。(被final修饰过的方法或字段是不能覆盖的) (3)字节码验证 主要的目的是通过对数据流和控制流的分析,确定程序语义是合法的、符合逻辑的。 (4)符号引用验证:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量

为类变量分配内存并设置类变量初始值

把类中的符号引用转换为直接引用 比如:方法中调用了其他方法,方法名可以理解为符号引用,而直接引用就是使用指针直接指向方法。

对类的静态变量,静态代码块执行初始化操作