Java内存区域

来源:互联网 发布:淘宝颜色分类自定义 编辑:程序博客网 时间:2024/06/07 03:59

java虚拟机内存区域大致可以分为方法区、java堆;java虚拟机栈、本地方法栈和程序计数器五部分

在上述的五部分中,方法区和java堆是所有线程共享的,而虚拟机栈、本地方法栈和程序计数器是线程隔离的,每个线程产生一个独立的区域

  1. java堆
    java堆是虚拟机内存创建的最大的一块内存区域,该内存区域由所有线程共享,在虚拟机启动的时候创建。
    几乎所有的实例对象都在该区域存放(随着技术的发展,变得不再是绝对)
    java堆是垃圾收集器管理的主要区域(回收,分配等细节后续再写)。
    java堆可以是物理上不连续的内存区域,逻辑上是连续的即可。在创建的时候,可以是固定的大小,也可以是可扩展的。
    当堆中出现没有内存可以分配且无法扩展的时候,会抛出异常(OutOfMemoryError).

  2. 方法区
    方法区是由所有线程共享的一个内存区域,是由虚拟机启动的时候创建,该区域和java堆类似。
    该区域主要存放虚拟机加载的类信息、常量、静态变量、即时编译器编译的代码,除此之外,方法区还有一个非常重要的区域被称为运行时常量池,用于存放在编译期生成的各种符号引用和字面量。
    方法区在粗略的划分中会与java堆归结到一起,但是两者略有区别:除了可以和java堆一样实现物理上不连续的内存外,方法区还可以选择不实现垃圾收集。该区域实现垃圾收集的目标主要是针对常量池的回收和对类型的卸载。
    方法区无法满足内存分配需求时会抛出OutOfMemory异常。

  3. 程序计数器
    程序计数器是指当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变程序计数器的值来选取下一个需要执行的字节码指令,分支、跳转、异常、循环、线程恢复等功能都依赖计数器完成。
    每个线程都会创建一个独立的程序计数器,各线程的程序计数器之间相互独立,互不影响。该内存是线程私有的内存。
    如果线程执行的是一个java方法,程序计数器记录的是当前虚拟机执行的字节码指令的地址,如果执行的是一个native方法,计数器为空(undefined).
    程序计数器没有OutOfMemoryError异常。

  4. 虚拟机栈
    虚拟机栈是线程私有的内存区域,其生命周期与线程的生命周期相同。
    每个方法执行的时候都会创建一个栈帧,用来存放局部变量表、操作数栈、动态链接、方法出口等信息。栈中最主要的是局部变量表部分。
    局部变量表存放了编译器可知的基本的数据类型(int、Boolean、double、float、byte、char、short、long)、对象引用(不是对象本身)以及returnAddress类型(指向一条字节码的地址)。
    在编译期间创建的各种数据类型的大小是固定的,所以栈帧的大小也是固定不变的,方法运行期间不会改变其大小。
    如果线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverFlowError,当栈可以扩展的情况下,无法申请到足够的内存,那么会抛出OutOfMemoryError异常。

  5. 本地方法栈
    本地方法栈与虚拟机栈类似,两者之间的区别不过是虚拟机栈是为虚拟机执行java方法(字节码)服务,而本地方法栈是为虚拟机执行native方法服务。
    部分情况下本地方法栈和虚拟机栈会归类到一起。
    跟虚拟机栈一样,本地方法栈也会抛出StackOverFlowError和OutOfMemoryError两种异常。

  6. 直接内存
    直接内存不是java虚拟机中创建的内存区域。
    在JDK中,I/O类中有一种基于通道和缓冲区的I/O方式,它可以使用native函数库直接创建一个java堆外内存,然后通过java堆中的DirectByteBuffer对象作为这块内存的引用对这块内存进行操作。
    直接内存的大小不受java堆大小的限制,但受限于物理内存大小限制,也会抛出OutOfMemoryError异常。
原创粉丝点击