Java内存区域

发布于:2022-12-16 ⋅ 阅读:(18042) ⋅ 点赞:(18)

在这里插入图片描述

程序计数器

作用:存储下一条JVM指令的执行地址(当前线程所执行的字节码的行号指示器)

java代码在编译过程中,会被转化为JVM指令(二进制字节码)。二进制字节码通过字节码解释器解释为机器码,才能经CPU处理。这个过程中,程序计数器时刻指向下一条JVM指令地址。

特点:

  • 线程私有:每条线程具有独立的程序计数器,各条线程之间程序计数器互不影响,独立存储。
  • 唯一一个不存在内存溢出(OutOfMemoryError)的区域

虚拟机栈

虚拟机栈:每个线程运行时所需要的内存空间

栈帧:方法调用时所需要的内存空间

每个栈由多个栈帧组成,对应着每次调用方法时所占用的内存。每个线程只能有一个活动栈帧,对应着当前正在执行的方法。

两种异常状况

  • StackOverflowError

如果线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常。如栈帧过多或过大。

  • OutOfMemoryError

虚拟机栈可以申请动态扩展。当扩展时无法申请到足够内存时,抛出OutOfMemoryError异常

特点:

  • 栈是线程私有
  • 垃圾回收不涉及栈内存
  • 当扩展时无法申请到足够内存时,抛出OutOfMemoryError异常

本地方法栈

作用同虚拟机栈。

不同点在于:本地方法栈为虚拟机使用到的 Native 方法服务;虚拟机栈为虚拟机执行 Java 方法(字节码)服务。

也会抛出StackOverflowErrorOutOfMemoryError异常。

Java堆

Java虚拟机管理的内存最大的一块区域,用于存放对象实例,在虚拟机启动时创建。

特点:

  • Java堆是被所有线程共享的内存区域。
  • 存在垃圾回收机制
  • 当堆中没有内存完成实例分配,并且堆无法扩展时,抛出OutOfMemoryError异常。

根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间,只要逻辑上连续即可。在实现时,可实现成固定大小,也可实现堆空间扩展(通过 -Xmx 和 -Xms 控制)。

方法区

用于存储已被虚拟机加载的类信息、常量(运行时常量池)、静态变量等数据。

特点:

  • 方法区是线程共享的内存区域
  • 可以选择不实现垃圾回收
  • 当方法区无法满足内存分配需求时,抛出OutOfMemoryError异常

Java虚拟机规范规定:方法区不需要连续的内存;可以选择固定大小或可扩展;可以选择不实现垃圾回收。

方法区垃圾回收目标主要是针对常量池的回收和对类型的卸载

运行时常量池

常量池:**用于存放编译期生成的各种字面量和符号引用。**虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量信息
运行时常量池
常量池是*.class文件中的,当该类被加载以后,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

运行时常量池具有动态性。常量并不一定只在编译期间产生,运行期间也可能将新的常量放入池中。常见例子:intern()方法

运行时常量池是方法区的一部分,与方法区相同,可以抛出OutOfMemoryError异常

直接内存

  • 常用于NIO操作,用于数据缓冲区
  • 分配和回收成本高,但读写较快
  • 不受垃圾回收机制管理

直接内存并不是虚拟机定义的内存区域,但是这部分内存也会被频繁使用,并且动态扩展时可能抛出OutOfMemoryError异常

在IO的过程中,Java无法直接操作磁盘文件,而是使用本地方法操作和读取磁盘文件。这个过程是在系统内存中创建缓冲区,将数据读取到系统缓冲区,随后将缓冲区数据拷贝至堆内存中。

JDK1.4引入了一种基于通道和缓冲区的IO方式(NIO)之后,可以使用Native函数库直接配堆外内存,然后通过DirectByteBuffer对象操作这块内存。避免了在Java堆和Native堆中来回复制数据,可以显著提升性能

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到