文章目录
  1. 1. 背景
  2. 2. JVM结构

背景

为什么要使用虚拟机?从编程语言的演变发展来看,开关-》二进制-》汇编-》C语言-》C++-》java,经过一层层抽象,为了跨平台,最终形成了虚拟机,其中的发展细节可以参考《编码:隐匿在计算机软硬件背后的语言》。java程序经过编译器编译,生成java字节码,再由java虚拟机加载字节码,最终生成目标代码,用户端源码不用修改就可以跨平台运行。

JVM结构

jvm内部结构图:

jvm内部结构

红色框部分表示线程私有变量,method area、heap为线程共享部分。runtime data areas 5块内容介绍:

  • 程序计数器(program counter register):JVM每个线程都有自己的PC,通过PC去找到自己的执行方法,线程执行如下图所示:
    线程执行图

  • JVM栈(stack):如上图所示,在JVM线程执行方法时,在内部都有一个栈空间,栈的作用就是存储Frame结构,里面包含了各种参数(方法参数,成员变量参数,返回值参数等等)引用:
    JVM栈
    栈空间经常有两个异常是和它先关的:

1.StackOverflowError,当执行线程的方法栈的容量大于JVM可允许的容量时,就抛出StackOverflowError(纵向比较)
2.OutOfMemoryError,栈内存可以动态扩展,虽然内存不足,但是允许为每个线程初始化栈空间,这时就会抛出OutOfMemoryError(横向比较)

  • 本地方法栈( Native Method Stacks)
    俗称”C Stack”,如果有本地方法,每个执行线程会单独的创建一个C stack。这里也有可能有两个错误异常,原因和栈空间一样。

  • 堆空间(heap)
    用于存储类实例以及数组分配的空间,JVM线程可以共享该区域。垃圾收集器回收利用对象就是在这个区域实现的。堆空间不需要连续的,内部是有向图数据结构,而栈空间是连续的。堆空间可以通过外部命令设置空间大小,如果程序运行期间堆空间的容量大于JVM设置的堆空间最大容量,就会抛出OutOfMemoryError。

  • 方法区域(Method Area)
    逻辑上是堆空间的一部分,线程也可以共享,它存储了每个类(.class)的常量、属性、方法以及构造方法,它有最大、最小空间阈值,如果方法区域空间不能满足请求分配的容量(超出最大阈值),就会抛出OutOfMemoryError。方法区内部还有一块运行时常量池(Runtime Constant Pool),编译生成的各种常量就会存到该区域,如果存储容量超过方法区的限制,也会抛出OutOfMemoryError。

最后说下,虚拟机之外还有一块直接内存,由JDK1.4NIO引入,它通过DirectByteBuffer存储到堆内存,堆里面只是引用,实际它的大小限制是不受JVM控制的,如果这块内容大于实际物理内存也会抛出OutOfMemoryError。了解虚拟机目的是为了排查处理系统可能遇到的问题,而不是研发性质的,如果一天能花20%的时间了解虚拟机的一个大概内容,对后面JVM调优、问题排查还是很有帮助。

参考资料:
《Inside the Java 2 Virtual Machine》
《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》

文章目录
  1. 1. 背景
  2. 2. JVM结构