Java内存区域与内存溢出异常

Java内存区域与内存溢出异常

Java虚拟机在执行Java程序的过程中会把它管理的内存分为不同的若干个数据区域。

具体的情况如下图所示:

jvm
jvm

我们可以可到运行时数据区主要有以下几个部分组成:

  1. 程序计数器(Program Counter Register)
  2. Java虚拟机栈(VM Stack)
  3. 本地方法栈(Native Method Stack)
  4. Java堆(Heap)
  5. 方法区

我们一个个看分析一下这些部分的功能和特点。

程序计数器(Program Count Register)

程序计数器是一块比较小的内存区域,它的作用是:当前线程所助兴的字节码的符号显示器。

这里有一个需要注意的地方,即【当前线程】,也就是说程序计数器是每个线程独享的,它用于在线程切换后能恢复到上一次的正确执行位置。

这个区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

Java虚拟机栈

Java虚拟机栈也是线程私有的,它的生命周期与线程相同。

这一部分描述的是Java方法执行的内存模型:

每个方法被执行的时候都会创建一个栈帧(Stack Frame),用于存储局部变量表等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧从入栈到出栈的过程。

在虚拟机栈中最重要的部分是局部变量表, 存放了编译期可知的基本数据类型,对象引用等等。

局部变量表所需的内存空间在编译期完成分配。

这个区域可能抛出两种异常:

  1. 如果线程请求的栈深度大于虚拟机所允许的深度: 抛出StackOverflowError
  2. 如果虚拟机栈可以动态扩展,当扩展无法申请到足够内存时,抛出OutOfMemoryError

本地方法栈

本地方法栈与虚拟机栈基本一致,不同的是本地方法栈是位虚拟机使用到的Native方法服务的。在有些虚拟机中(Sun HotSpot),直接把本地方法栈和虚拟机栈合二为一了。

Java堆

我们尝试总结Java堆的特性如下:

  • Java堆是被所有线程共享的一块内存区域
  • 在虚拟机启动时创建
  • 这一区域的目的是:存放对象实例
  • Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”
  • Java堆可以处于物理上不连续的内存空间,只要在逻辑上连续就行了

方法区

与Java堆一样,方法区也是线程共享的内存区域。

它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等等。

垃圾收集行为在这个区域比较少见,回收目标主要是常量池的回收和对类型的卸载。

运行时常量池(Runtime Constant Pool)

运行时常量池是方法区的一部分,用于存放编译器生成的各种字面量和符号引用。

运行时常量池具备动态性,运行期间也可以将新的常量放入池中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容