# 运行时内存

# 运行时数据内存

  • 方法区

用于储存已被虚拟机加载的 类信息、常量、静态变量、即时编译器编译后的代码 等数据。
这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载。
当方法区无法满足内存分配需求时,将抛出OutOfMemoryErroy异常。

  • 虚拟机栈

描述的是Java方法执行的内存模型。
每个方法在执行的同时都会创建一个栈帧用于储存 局部变量表、操作数栈、动态链接、方法出口 等信息。
每个方法从调用直至完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。 栈内存就是虚拟机栈,或者说是虚拟机栈中局部变量表的部分。 Java虚拟机规范对这个区域规定了两种异常状况: StackOverflowError,线程请求的栈深度大于虚拟机所允许的深度 OutOfMemoryError,如果虚拟机扩展时无法申请到足够的内存

  • 本地方法栈

虚拟机栈为虚拟机执行Java方法(也就是字节码)服务 而本地方法栈则为虚拟机使用到的Native方法(Native Method就是一个Java调用非Java代码的接口)服务。

是Java虚拟机所管理的内存中最大的一块。

Java堆是被所有线程共享的一块内存区域,在虚拟机启动的时候创建,此内存区域的 唯一目的是存放对象实例 几乎所有的对象实例都在这里分配内存,所有的对象实例和数组都在堆上分配。

Java堆是垃圾收集器管理的主要区域,Java堆细分为新生代和老年代。
不管怎样,划分的目的都是为了更好的回收内存,或者更快地分配内存。

Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。 如果在堆中没有完成实例分配,并且堆也无法再扩展时将会 抛出OutOfMemoryError异常 。

  • 程序计数器

  • 小结

方法区和堆 是由 线程共享的 数据区,其他几个是线程隔离的数据区。
程序计数器,虚拟机栈,本地方法栈,随线程而生,线程亡而亡。

# 运行时常量池

它是方法区的一部分,用于存放编辑期生成的各种字面量和符号引用。
这部分内容将在类加载后进入方法区的运行时常量池中存放。 Java语言并不要求常量一定只有编辑期才能产生,也就是可能将新的常量放入池中,
这种特性被开发人员利用得比较多的便是String类的intern()方法。
当常量池无法再申请到内存时会 抛出OutOfMemoryError异常 。

# 局部变量表

存放了编辑期可知的各种基本数据类型,
对象引用(refrence)类型和returnAddress类型(指向了一条字节码指令的地址)
其中64位长度的 long 和 double 类型的数据会占用两个局部变量空间,其余的数据类型只占用1个。

局部变量表所需的内存空间在编译器间完成分配 当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

# 直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。 NIO类是一种基于通道和缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,
然后通过一个储存在Java堆中的DirectByteBuffer对象作为这块直接内存的引用进行操作,这样避免了Java堆和Navie堆中来回复制数据。