Fork me on GitHub

Java虚拟机的架构

1

类加载子系统: 负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间。除了类信息外,方法区中可能还会存放运行时常量池信息,包括字符串字面量和数字量(这部分常量信息是Class文件中常量池部分的内存映射)。当JVM使用类加载器装载某个类时,它首先要定位对应的Class文件,然后读入这个Class文件,最后,JVM提取该文件的内容信息,并将这些信息存储到方法区,最后返回一个Class实例。
方法区: 方法区主要存储的是方法,静态成员,常量。方法区中给每个类都规定了空间并且持有this和super的引用。当运行到哪个对象的时候,通过this动态指向该对象,引用该对象的成员变量,然后和方法以及局部变量一起在栈中进行运算。方法区的大小不必是固定的,默认最小值为16MB,最大为64MB,JVM可根据应用需要动态调整。同时,方法区也不一定是连续的,方法区可以在一个堆(甚至是JVM自己的堆)中自由分配。
Java堆: Java堆是在JVM启动的时候就建立的,是java程序最主要的内存工作区域。堆空间是所有线程共享的。这块内存区域存放了对象实例及数组(所有new的对象)也就是Object object= new Object();这里object只是一个引用是放在栈里面的,new Object()被放在了堆内存里面。由于现在收集器都是采用分代收集算法,堆被划为新生代和老年代。新生代主要存储所创建的对象和尚未进入老年代的对象,老年代存储经过多次新生代GC(Minor GC)仍然存活的对象。
直接内存: Java的NIO库允许Java程序使用直接内存。直接内存是在Java堆外的、直接向系统申请的内存空间。通常,访问直接内存的速度会优于Java堆。因此出于性能考虑,读写频繁的场合应考虑使用直接内存。因为直接内存不在java堆内,因此直接内存的大小不会直接受限于jvm参数-Xmx,而它和java堆的总和,受制于操作系统的内存大小。
垃圾回收系统: 这是JVM的重要组成部分,垃圾回收器可以直接对方法区、Java堆和直接内存进行回收。在其中Java堆则是垃圾回收器的重点工作区域,对于不在使用的垃圾对象,垃圾回收系统会在后台查找标识,并且释放这些不用的垃圾对象。
Java栈: 每一个线程中都有私有的Java栈,一个线程的Java栈在线程被创建的时候就会被创建。Java栈由许多栈帧组成,一个栈帧包含一个Java方法调用的状态。当线程调用要给Java方法时,虚拟机压入一个新的栈帧到该线程的Java栈中,当该方法返回时,这个栈帧就从Java栈中弹出。Java栈中存储线程中Java方法调用的状态包括:局部变量、方法参数、返回值以及运算的中间结果等,并且对象的引用也存在栈中。Java虚拟机没有寄存器,其指令集使用Java栈来存储中间数据。这样设计的原因是为了保持Java虚拟机的指令集尽量紧凑,同时也便于Java虚拟机在只有很少通用寄存器的平台上实现。另外,基于栈的体系结构,也有助于运行时某些虚拟机实现的动态编译器和即时编译器的代码优化。
本地方法栈: 任何本地方法接口都会使用某种本地方法栈。当线程调用Java方法时,虚拟机会创建一个新的栈帧并压入Java栈。当它调用的是本地方法时,虚拟机会保持Java栈不变,不再在线程的Java栈中压入新的栈,虚拟机只是简单地动态连接并直接调用指定的本地方法。其中方法区和堆由该虚拟机实例中所有线程共享。当虚拟机装载一个class文件时,它会从这个class文件包含的二进制数据中解析类型信息,然后把这些类型信息放到方法区。当程序运行时,虚拟机会把所有该程序在运行时创建的对象放到堆中。像其它运行时内存区一样,本地方法栈占用的内存区可以根据需要动态扩展或收缩。
PC寄存器: PC寄存器也是每个线程私有的空间,Java虚拟机会为每个Java线程创建PC寄存器。在任意时刻,一个Java线程总是在执行一个方法,这个正在被执行的方法称为当前方法。如果当前方法不是本地方法,PC寄存器就会指向当前正在被执行的指令,若是本地方法,则PC的值就是undefined。
执行引擎: 最核心的组件之一,负责执行虚拟机的字节码。现代虚拟机为了提高执行效率,会使用即时编译技术将方法编译成机器码后再执行。

Your support will encourage me to continue to create!