2016 May 23 Java
Java 内存模型
Java 执行流程
- java源文件经过java编译器,编译过后生成.class的字节码文件
- 然后jvm的类加载器加载.class文件,
- 加载完成后,jvm的执行引擎执行class中的指令
- 将执行过程中所用的数据(类信息,对象等等)存储在运行时数据区(runtime data area)中,运行时数据区,就是jvm内存了。
Java 内存模型
程序计数器:类似PC寄存器的概念,存储当前线程执行字节码指令的行数。
- 当线程执行java方法时,计数器记录的是jvm执行字节码指令地址;
- 当线程执行native方法时,计数器的值为undefined(因为,native方法是交给系统来执行的,没有’PC 寄存器’的概念,对应的地址值,也就不存在了。)
- 由于cpu内核,在同一时刻只能执行一条指令,为了保证java多线程正确执行,每个线程都有一个程序计数器,因此,程序计数器是线程私有的。
虚拟机栈:一个线程的每个方法在执行的同时,都会创建一个栈帧(Statck Frame)。java栈中存放的是一个个的帧栈,每个帧栈包括:局部变量表,操作数栈,运行时常量池的引用,方法返回地址,附加信息。
- 当线程请求栈深度超出虚拟机所允许的深度时,会抛出StackOverFlowError
- 当java虚拟机动态扩展到无法申请的内存时,会抛出OutOfMemoryError
- 栈帧:
- 局部变量表:局部变量表存储的是基本数据类型和引用数据类型
- 操作数栈:线程执行方法的过程,实际上就是执行语句的过程,归根到底就是计算机计算的过程。然而程序中所有的计算都是借住于操作数栈来完成的。可以理解成,它就是用来做计算的。
- 运行时常量池的引用:方法运行过程中,可能用到类的常量,方法区中的静态对象,因此需要一个指向这些运行时常量的引用。
- 方法返回地址:正常退出:执行引擎遇到方法返回的字节码,将返回值传递给调用者,异常退出:遇到Exception,并且方法未捕捉异常,那么不会有任何返回值
- 附加信息:虚拟机规范没有明确规定,由具体虚拟机实现,可能是一些调试的信息
本地方法栈:和虚拟机栈类型,只不过本地方法栈为native方法服务,虚拟机栈为java方法服务,HotSpot虚拟机直接将本地方法栈和虚拟机栈合并在一起。
- 当线程请求栈深度超出虚拟机所允许的深度时,会抛出StackOverFlowError
- 当java虚拟机动态扩展到无法申请的内存时,会抛出OutOfMemoryError
堆区:存储对象本身和数组,占用内存最大的一块区域。java堆,是垃圾收集器管理的主要区域,也成为GC堆。目前,基本上所有的jvm都采用了分代收集算法,将java堆,分为年轻代,年老代,持久代。
- 从内存回收的角度来看,java堆被分为年轻代,年老代,持久代,这样划分的好处在于对不同生命周期的对象,采用不同的回收算法,使得内存回收更加快速。
- 从内存分配的角度来看,虽然java堆是线程共享的,但是它也划分出线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB),这样分配内存就更快了。
- 当java虚拟机动态扩展到无法申请的内存时,会抛出OutOfMemoryError
方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,和java堆一样,是一块线程共享的区域。
