Java 内存模型是面试官最喜欢问的问题之一。
Java 内存在逻辑功能上分成 5 个区。方法区,堆区,JVM 栈,方法栈,程序计数器(PC 寄存器)。
其中方法区,堆区是所有线程都共享的。JVM 栈,方法栈,程序计数器(PC 寄存器)是每个线程都有独立的一份。
JVM 栈就是程序运行时候的栈,局部变量之类的都存放与此,函数的调用和结束,对应的就是元素的入栈和出栈。递归调用深度过深的话,就会出现 StackOverflow 的错误。JVM 栈中有很多栈帧,每个栈帧都对应一个被调用的方法,栈帧中有局部变量表,用来存储方法中的局部变量。由于每一个线程都有自己的 JVM 栈,所以运行时是互不干扰的。
本地方法栈和 JVM 栈类似,区别就是 JVM 栈运行的 Java 代码,本地方法栈运行的是 NativeCode。
方法区,存放的是 JVM 加载的类的信息,各种静态变量等信息,是全局共享的。Java8 中已经移除了方法区,增加了一个叫做元空间的本地内存区,不过元空间与方法区是有区别的,元空间使用的是本地内存,而不是 JVM 中划分的。所以,元空间的大小仅和本地内存大小有关,元空间的大小可以通过参数来设置。
Java1.7 之前,字符串常量池存放在方法区,Java1.7 之后移到了堆区。
堆区就是所有的实例对象都放在里面,所有的线程都能访问,垃圾回收也主要在这里发生。根据 Java 虚拟机规范的规定,Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出 OutOfMemoryError 异常。
程序计数器也称作 PC 寄存去,和汇编程序中的 CPU 寄存器概念是类似的,都是用来指示执行的之类地址。每个线程都有各自的程序计数器,互相独立互不干扰。
Java 内存模型划分就是以上几种。但是细究下去还有其他的更多的知识点,比如原子性,可见性等概念。会在后续的文章中讨论。