1、类装载子系统:装载 连接 初始化
2、方法区。被所有线程共享。垃圾收集也会清理方法区中的无用类型对象。
a. 类型信息。类加载器加载类时,从类文件中提取出来:类的完整有效名、父类的完整有效名(interface and java.lang.Object 除外,因为无父类)、类型的修饰、类型直接接口列表
b. 常量池。存储了一个类型所使用的常量所有类型、域和方法的符号引用。
c. 域信息。jvm必须在方法区中保存类型的所有域的相关信息以及域的声明顺序,
域的相关信息包括:域名、域类型、域修饰符(public private protected static final volatile transient…)
d.方法信息:方法名、方法返回类型、方法参数、方法的修饰符、方法的字节码(abstract and native 除外)(被PC寄存器指向)、操作数栈和方法栈帧的局部变量区的大小、异常表
e. 类的静态变量(所有对象共享一分拷贝)
f. 类的被声明为final的类变量(所有对象共享一分拷贝)
g. 加载一个类的类加载器的引用
h. Class类的引用
i. 方法表。
3、堆。Java程序在运行时创建的所有类实例或数组都是从堆中分配空间,一个Java虚拟实例中只存在一个堆空间因此所有线程都将共享这个堆。每一个java程序独占一个JVM实例,因而每个java程序都有它自己的堆空间,它们不会彼此干扰。但是同一java程序的多个线程都共享着同一个堆空间,就得考虑多线程访问对象(堆数据)的同步问题。 (这里可能出现的异常java.lang.OutOfMemoryError: Java heap space)。堆的管理是由垃圾回收来负责的
4、java栈。当JVM创建一个新线程时,都会产生线程计数器(PC Register)和栈。线程的每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表、操作栈、动态链接、方法出入口等信息。每一个方法的调用至完成,就意味着一个帧在VM栈中的入栈至出栈的过程。如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果VM栈可以动态扩展(VM Spec中允许固定长度的VM栈),当扩展时无法申请到足够内存则抛出OutOfMemoryError异常
5、PC 寄存器 ( 程序计数器 )
Java虚拟机的寄存器用于保存机器的运行状态, 与微处理器中的某些专用寄存器类似,每个线程拥有自己的程序计数器,它指向下一条指令,指令的位置放在方法区的方法字节码中,内容是相对于第一个指令的偏移量。当线程调用本地方法的时候, 它为undefined。
6、本地方法栈。对于一个运行中的Java程序而言,它还可能会用到一些跟本地方法相关的数据区。当某个线程调用一个本地方法时,它就不再受到虚拟机关于结构和安全限制方面的约束,它既可以访问虚拟机的运行期数据区,也可以使用本地处理器以及任何类型的栈。当JVM线程调用了本地方法, 则会跳入本地方法栈。本地方法返回后可能再次跳回java方法栈。
7、执行引擎。处于JVM的核心位置,在Java虚拟机规范中,它的行为是由指令集所决定的
8、本地方法接口。实现JVM并不要求一定要有它的支持,甚至可以完全没有。Sun公司实现Java本地接口 (JNI) 是出于可移植性的考虑,当然我们也可以设计出其它的本地接口来代替Sun公司的JNI。但是这些设计与实现是比较复杂的事情,需要确保垃圾回收器不会将那些正在被本地方法调用的对象释放掉