那么我们在开始介绍Java内存区域之前,我们先放一张内存区域的图,方便我们后面介绍的时候可以对照着看。
「须知」,本文是根据JDK8来介绍的。
Java内存区域图
首先它是线程私有的,它也称为代码的行号指示器,字节码解释器就是通过改变程序计数器的位置来确定下一行要执行的代码,它不存在OOM。
如果线程正在执行一个Java方法,那么它记录的是正在执行虚拟机字节码指令的地址,如果是一个本地方法那么它的值为空。
它也是线程私有的,它的声明周期和线程一致。每个线程创建时都会创建一个虚拟机栈,内部保存了一个个的栈帧,每个栈帧就对应着一次方法的调用。既然知道了虚拟机栈里面存放的是一个个的栈帧,那么也不难猜出虚拟机栈里面都存储了什么东西。
Java虚拟机栈是存在OOM的,当线程所请求的栈的深度大于虚拟机栈的深度或者虚拟机栈可以动态扩容,当栈扩展时无法申请到足够的内存时,就会抛出OOM。
虚拟机栈内部结构
Java虚拟机栈为虚拟机执行Java方法服务,本地方法栈则为虚拟机使用到的本地方法服务。像JVM就有好多C语言写的方法,这个就需要本地方法栈来执行。
Java堆是虚拟机中最大的一块内存空间,它被所有的线程共享,在虚拟机启动时创建。它唯一的目的就是存放对象实例。
如果面试被问到,所有的对象实例都是在堆中分配内存吗?这个时候你一定要回答,不是。
随着即时编译技术的发展进步,尤其是逃逸分析技术的日渐强大,栈上分配、变量替换等优化手段,让实例在”只在堆“中分配不再成为绝对。
Java堆是垃圾收集的主要区域,Java堆中也经常出现新生代、老年代、永久代等等,这里需要注意,这些并不是Java堆物理上的内存布局,它是作为垃圾收集器而划分一种内存布局。
方法区也是线程共享的区域,它主要用于存储被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
方法区它是可以被垃圾收集器进行回收的,主要针对类型的卸载和常量池的回收。
方法区也可以产生OOM,当方法区无法满足新的内存分配需求时,将抛出OutOfMemoryError异常。
运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等信息外,还有一项信息是常量池表,它用来存储编译期生成的各种字面量和符号引用。
如果动态链接那块没看懂,那么看了运行常量池再翻回去看看是不是好理解
了。
参考书籍:
《深入理解Java虚拟机》