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

概述

Java 对于 C 和 C++ 来说存在一个很好的特性就是在虚拟机的自动内存管理机制的帮助下,不需要为每一个 new 操作去写配对的 delete/free 代码,而且**不容易** 出现内存泄漏和内存溢出问题。注意这里说的是不容易,所以还是有可能会出现的。那么当出现的时候就需要你能够排查和解决掉错误。

运行时数据区域

Java 虚拟机在执行程序的过程中会把所管理的内存划分为若干个不同的数据区域。每个区域用途不同,生命周期也不同,或随虚拟机进程产生和销毁,或随用户线程产生和销毁。其中有所有线程共享的数据区有:方法区(Method Area)、堆(Heap)线程隔离的数据区有:虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)、程序计数器(Program Couter Register)

程序计数器

在学操作系统的时候,我们知道进程是资源分配的基本单位,进程是调度的基本单位。线程基本上不拥有系统资源只拥有一些必不可少的资源其中就包括程序计数器。程序计数器的作用是当前线程所执行的字节码的行号指示器。Java 虚拟机的多线程是通过线程轮流切换并分配处理器的执行时间的方式来实现的,在任何一个确定的时刻,一个处理器只会执行一条线程中的指令。

Java 虚拟机栈

Java 虚拟机栈也是线程私有的,生命周期与线程相同。虚拟机栈描述的是 Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

一般在面试中都会问到关于Java 内存分区中的堆内存(Heap)与栈内存(Stack)问题。我曾经简单的以为就是数据结构中的栈一样呢。分为这两种分区是比较粗糙的分法,实际的情况比这更加复杂。“栈”就是虚拟机栈,或指的是虚拟机栈中的局部变量表部分。局部变量表所需的内存空间是在编译期间完成分配的,在运行期间不会改变大小。

在这个区域会产生两种异常的情况,一是 如果线程请求的栈的深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常,二是 如果虚拟机栈可以动态扩展,当扩展时无法申请到足够的内存时会抛出 OutOfMemoryError 异常。

本地方法栈

Native Method Stacks 与虚拟机栈所发挥的作用是非常相似的,虚拟机栈为虚拟机执行Java 方法服务,本地方法栈为虚拟机使用到的 Native 方法服务。因为虚拟机没有对本地方法栈中的方法是用的语言等强制规定,Sun HotSpot 将两者合二为一,本地方法栈区域同样会抛出 上述两种异常。

Java 堆

Java 堆(Java Heap)的几个特点

  1. Java 虚拟机所管理的内存中的最大一块
  2. 被所有线程共享的一块内存区域
  3. 虚拟机启动时创建
  4. 唯一目的存放对象实例
  5. 垃圾收集器管理的主要区域,也被称为 “GC堆”
  6. 可处于物理上不连续的内存空间
  7. 处于逻辑上连续的内存空间

在Java 规范中描述的是:素有的对象实例以及数组都要在堆上分配。但是目前来看不再是那么绝对了。

方法区

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

特点:逻辑上是Java 堆的一部分,但是别名叫做 Non-Heap(非堆)。它不需要连续的物理内存和可以选择固定大小或者可扩展,并且可以选择不实现垃圾收集。

当方法区无法满足内存分配需求时,将会抛出 OutOfMemoryError 异常。运行时常量池也是方法区的一部分,当常量池无法申请到内存时会抛出 OutOfMemoryError 异常。

直接内存

它不是虚拟机运行时数据区的一部分,也不是Java 虚拟机规范中定义的内存区域。当各个内存区域的总和大于物理内存限制,从而导师动态扩展时出现 OutOfMemoryError 异常。

对象访问

通过一句代码来看:

Object obj = new Object()

Object obj 这部分语义反映到 Java 栈的本地变量表中,作为一个 reference 类型数据出现。 new Object() 这部分的语义将会反映到 Java 堆中,形成一块存储了 Object 类型所有实例数据值的结构化内存,此内存长度不固定。虚拟机访问对象的方式主要分为两种:

  • 使用句柄
  • 直接指针

句柄访问优势在于 reference 中存储的时稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。

直接指针访问的优势在于 速度更快,它节省了一次指针定位的时间开销。

发布者

Avatar photo

常轩

总要做点什么吧!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注