《深入理解Java虚拟机》出第三版了,工作一年多的时候看过第二版,重新复习一遍JVM
一、内存分配
JVM管理的内存包括5个运行时数据区域。
- 线程私有:程序计数器,虚拟机栈,本地方法栈
- 线程共享:堆,方法区
1、程序计数器PC
①程序计数器的作用
JVM中程序计数器是一块很小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。
即Java文件编译成class文件后,会被编译成很多字节码指令,例如iadd,istore等,
程序计数器是用来记录当前线程正在执行的字节码指令的地址,如果执行的是本地方法,计数器为Undefined
它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等都是需要依靠PC来完成的
PS : CPU中也有一个PC寄存器,作用是保存下一条CPU指令的地址,默认是每次执行指令后+1。
②程序计数器的由来
JVM的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的(《操作系统原理》中进程调度策略:时间片轮转法),
单核处理器在一个时间片内,仅能处理一个线程中的字节指令,时间片结束后,进入下一个时间片,单核处理器会处理另一个线程的字节码指令,
为了线程切换后能恢复到正确的位置,每条线程都需要有一个独立的程序计数器,独立存储--即程序计数器是线程私有的内存。
③内存溢出
程序计数器是唯一一个没有规定任何OutOfMemoryError情况的内存区域。
2、Java虚拟机栈
Java虚拟机栈也是线程私有的,它的生命周期与线程相同。
① Java虚拟机栈的作用
虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,都会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法被调用直至执行完毕的过程,对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
② 局部变量表
局部变量表:存放编译期可知的各种Java虚拟机
- 基本数据类型(boolean,byte,char,short,int,float,long,double)、
- 对象引用类型(reference:指向对象起始地址的指针或者句柄)
- returnAddress(指向一条字节码指令的地址),
局部变量表是以槽(Slot)为单位表示的,Slot大小为32bit,PS:long与double大小是64bit,需要两个Slot存储,不具备原子性,不是线程安全的。
局部变量表所需的内存空间在编译期间完成分配的,即编译期已经固定了内存大小,运行期间不会改变局部变量表的大小。
//很有意思的问题,下面两种写法中, //在编译期就已经确定了栈帧中局部变量表的大小 public void test(){ for(int i = 0; i < 10000; i++){ //这里不会创建10000个reference引用,每次超出作用域范围,旧的obj都会被覆盖 //所以跟下面写法,区别不是很大,不会引起栈溢出 //优点可能就是,尽可能缩小引用的作用域范围 Object obj = new Object(); } } public void test(){ Object obj; for(int i = 0; i < 10000; i++){ //这里引用的作用与范围,比上面要广 //但是由于没有引用所以,object对象GC可能会快一点。 obj = new Object(); } }
③内存溢出
虚拟机栈区域会出现两种异常状况
栈溢出:如果线程请求的栈深度大于虚拟机所允许的站深度,将抛出StackOverflowError异常
内存溢出:如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。
常见的HotSpot虚拟机栈是不可以动态扩展,所以不会由于扩展而导致的OOM异常,即只要线程申请栈空间成功之后就不会有OOM异常,申请栈失败还是会发生OOM异常的。
3、本地方法栈
本地方法栈返回的作用与虚拟机栈的作用非常类似,线程私有的,并且本地方法栈为仅为虚拟机用到的本地方法服务。
与虚拟机栈相同,本地方法栈也会出现栈溢出与内存溢出。
常见的HotSpot虚拟机将本地方法栈和虚拟机栈合二为一了。
4、堆
①堆的作用
Java Heap是JVM中所管理内存中最大的一块,是线程共享的。
Java Heap是在JVM启动时创建的,它的唯一作用就是存放对象实例。《Java虚拟机规范》中“所有的对象实例以及数组都应当在堆上分配”。
Java Heap是垃圾收集器管理的内存区域,所以也称为“GC堆”,GC会在后面学习
②TLAB
TLAB全称Thread Local Allocation Buffer,从分配内存的角度看,所有的线程共享的Java堆中可以划分出多个线程私有的分配缓存区TLAB。
TLAB的作用就是保证A线程创建Object,B线程创建Object在堆中的内存的
5、方法区