一、JVM

这是一张流程图
JVM主要由三部分组成:类加载区、运行时数据区和执行引擎。

类加载区

类加载区是JVM的“入口”。其负责找到并加载编译好的.class文件,并将这些二进制数据放到运行时数据区的方法内。

  1. 加载:通过类的全限定名、获取定义此类的二进制字节流。
  2. 链接:将加载到内存中的类的二进数据合并到JVM的运行状态中。流程:验证->准备->解析
  3. 初始化:执行类的构造器(clinit)方法,为静态变量赋予正确的初始值。

运行时数据区(JVM内存模型)

JVM在执行Java程序时,为“安放”各种数据而划分的内存区域,它是JVM的核心,老生常谈的JVM调优,主要就是针对该区域。

  1. :这是JVM管理中最大一块内存区域,也是所有线程共享的区域。它几乎存放了所有的对象实例,也是垃圾回收器管理的主要区域,因此也被称为“GC堆”。
  2. 方法区(元空间):这也是线程共的享区,它存储了每个类的构造信息,如运行时常量池*、字段和方法数据、构造函数、以及普通方法代码。Java8之后的方法区的实现被称为“元空间”。
  3. 虚拟机栈:这是线程私有的,它的生命周期与线程相同。每个方法被执行的时候,JVM都会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法的调用直到执行完成,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。我们常说的“栈内存”就是指这个区域,它存放的是基本数据类型对象的引用
  4. 本地方法栈:这也是线程私有的。它的作用和虚拟机栈非常相似,区别在于虚拟机栈为Java方法(字节码)服务,而本地方法栈为Native方法服务(通常由其他语言如C/C++编写)。
  5. 程序计数器:这是线程私有的,内存空间很小。它可以看作是当前线程所执行的字节码的行号指示器。字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,从而实现分支、循环、跳转、异常处理、线程恢复等基础功能。
运行时常量池:JVM在方法区中分配的一块内存区域,用于堆放类或接口编译期生成的各种字面量和符号引用

执行引擎

执行引擎是JVM的驱动器,负责执行字节码指令。

  1. 解释器:它负责“解释”和执行字节码。它的工作方式就像同声传译,读一行字节码,解释一行,然后执行一行。优点是启动速度快。
  2. 即时编译器:当JVM发现某个方法或代码块运行特别频繁(即所谓的“热点代码”)时,即时编译器就会介入,把这些热点代码直接编译成与本地平台相关的机器码,并进行各种层次的优化。编译完成后,当这段代码再次被调用时,就可以直接运行这些编译好的机器码,从而获得极高的执行效率。
  3. 垃圾回收器:它是JVM的“自动内存管家”。在程序运行过程中,它会自动检测并回收那些不再被任何对象引用的“垃圾对象”,释放它们占用的堆内存。

总结

JVM本质上是一个规范。它定义了Java程序运行所需的一系列抽象结构,如类加载机制、内存布局、字节码执行流程等。我们常说的JVM,实际上是这个规范的具体实现版本(比如HotSpot VM)。它通过软件的方式,在不同的操作系统上模拟出一台“Java专用计算机”,从而实现了Java最核心的口号:“一次编写,随处运行”。

二、Java的错误和异常处理(Throwable)

Trowable是Java语言中所有错误和异常的父类。

Error(错误)

Error是Throwable的一个子类,表示严重的系统错误,通常由JVM抛出,应用程序不应尝试捕获和处理。

VirtualMacheError(虚拟机错误)

VirtualMacheError是Error的一个抽象子类,表示Java的虚拟机出现错误或资源耗尽的情况。抛出该错误通常意味着JVM已经处于不正常状态,应用程序无法自行恢复。

OutOfMemoryError(内存溢出错误)

OutOfMemoryError是VirtualMacheError的子类,当Java虚拟机因内存不足而无法分配对象时抛出的异常。

  1. Java heap space 堆中无法再分配新对象,可能是对象创建过多或存在内存泄漏。
  2. PermGen space (Java 7及以前) Metaspace(Java 8及以后)方法区实现被占满。
  3. unable to create new native thread 无法为新线程创建本地内存,通常是因为线程数过多或系统线程限制。

StackOverFlowError(栈溢出错误)

StackOverFlowError是VirtaulMachuneError的子类,当线程请求的栈深度超过虚拟机允许的最大深度时抛出。通常是由递归调用过深或方法调用链表过长导致。

InternalError(内部错误)

InternalError时VirtualMachineError的子类,表示Java虚拟机发生了内部错误。当JVM检测到其内部状态不一致、实现存在缺陷或遇到无法处理的意外情况时抛出。

UnknownError(未知错误)

UnknownError是VirtualMachineError的子类,表示Java虚拟机发生了未知类型的严重错误。当JVM遇到无法归类到其他已知错误类型的内部问题时抛出,是最不具体的VirtualMachineError。

AssertionError(断言错误)

AssertionError是Error的直接子类,表示断言失败。当Java程序中的assert语句条件未false时抛出,用于在开发和测试阶段捕获不应该发生的逻辑错误。

LinkageError(链接错误)

LinkageError时Error的直接子类,表示一个类依赖于另一个类,但后者在编译后发生了不兼容的改变,导致链接失败。当多个类之间存在依赖关系,但这种依赖关系在运行时无法满足时抛出。

ClassCircularityError(类循环依赖错误)

ClaasFormatError(类格式错误)

  1. UnsupportedClassVersionError(不支持的类版本错误)
  2. GenericSignatureFormatError(泛型签名格式错误)

NoClassDefFondError(类定义找不到错误)

VerifyError(验证错误)

ExceptionInInitializerError(初始化程序错误)

IncompatibleClassChangeError(初始化程序错误)

  1. AbstractMethodError (抽象方法错误)
  2. IllegalAccessError (非法访问错误)
  3. InstantiationError (实例化错误)
  4. NoSuchFieldError (字段找不到错误)
  5. NoSuchMethodError (方法找不到错误)
  6. UnsatisfiedLinkError (不满意链接错误)

BootstrapMethodError(引导方法错误)

ThreadDead(线程死亡)

TreadDead是Error的直接子类,是一个特殊的错误,当调用Therad.stop()方法时,会在目标线程中抛出,应用程序不应捕获该错误。

IOError(输入输出错误)

IOError时Error的子类,表示发生严重的I/O错误。与IOException不同,IOError时Error类型,表示程序无法恢复的严重I/O问题。

AWTError (Abstract Window Toolkit Error)

AWTError是Error的子类,表示AWT组件中发生的严重错误,通常与图形界面系统相关。

ZipError(压缩错误)

ZipError是Error的子类,表示在处理Zip文件时发生了严重错误。通常与Zip文件格式错误或损坏相关。

Exception

Exception是Throwable的一个子类,表示程序运行过程中可以处理的一些异常情况。Exception是可预见、程序应该处理的问题。

RuntimeException(运行时异常)

RuntimeException是Exception的特殊子类,表示在Java虚拟机正常运行期间抛出的异常。

NullPointerException (空指针异常)
IllegalArgumentException (非法参数异常)
  1. NumberFormatException (数字格式异常)

IndexOutOfBoundsException (下标越界异常)

  1. ArrayIndexOutOfBoundsException (数组下标越界)
  2. StringIndexOutOfBoundsException (字符串下标越界)

ArithmeticException (算术异常)

…….

IOException(IO异常)

IOException是Exception的直接子类,表示再输入输出操作中发生的异常。用于处理文件操作、网络通信、流处理等I/O任务中的错误情况。

SQLException(SQL异常)

SQLException是Exception的直接子类,提供关于数据库访问错误或其他错误的信息。

三、Java集合框架

这是一张流程图

Iterable接口

Iterable是所有可遍历集合的父接口。

Collection接口

Collection直接继承于Iterable:单列集合,直接存储单个元素。

  • 统一了所有单列集合的遍历方式,是 Stream API 的基础。

List接口(有序、可重复)

List顺序插入,允许存放重复元素,支持通过索引(下标)访问。

  1. ArrayList实现
  • 底层:动态数组
  • 特点:查询快,增删慢。ps:由于数组在内存中是连续的,通过索引查询快,但是在中间添加/删除元素需要移动插入/删除点之后的所有元素,慢。
  1. LinkedList实现
  • 底层:双向链表
  • 特点:查询慢,增删快。ps:查询需要从头开始遍历,慢,增删只需要修改前后元素的指针,快。
  1. Vector实现(JDK 17标记过时)
  • 底层:动态数组
  • 特点:使用synchronized关键字,线程安全。
  1. CopyOnWriteArrayList实现
  • 底层:写时复制数组
  • 特点:读操作无锁,写操作覆盖新数组,内存占用高,写性能差。用于替代Vector,线程安全。
  1. ImmutableList实现(JDK 9+)
  • 底层:固定长度数组
  • 特点:不可修改,无null元素,天然线程安全,性能优于同步集合。

Set接口(无序、不可重复)

  1. HashSet实现
  • 底层:基于HashMap
  • 特点:依赖hashCode()+equals()去重,无序,允许一个null元素,增删查效率极高。
  1. LinkedHashSet实现
  • 底层:基于HashMap+双向链表
  • 特点:继承自HashSet,额外维护插入顺序,去重且保护顺序。
  1. TreeSet实现
  • 底层:基于TreeMap(红黑树)
  • 特点:按自然顺序/自定义Comparator排序,无null元素,去重。
  1. CopyOnWriteArraySet实现
  • 底层:基于CopyOnWriteArrayList
  • 特点:写时复制,线程安全
  1. ImmutableSet实现(JDK 9+)
  • 底层:固定hash表
  • 特点:不可修改,无null元素,天然线程安全

Map接口

Map:双列集合,存储键值对