介绍下Java内存区域(运行时数据区)

2022-08-23 00:00:00 线程 对象 字符串 内存 方法

Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。JDK 1.8 和之前的版本略有不同。

下图是 JDK 1.8 对JVM做的改动,把方法区的具体实现----元空间已到了本地内存中。

各线程共享的:堆、方法区(元空间)、直接内存;

各线程私有的:程序计数器、虚拟机栈、本地方法栈;

1️⃣ 程序计数器

它是个什么?

程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。

它有什么用?

1、字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制;

2、在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了;

补充:

  • 每个线程内都有一个程序计数器,因为每个线程各自执行的指令地址是不一样的。当多线程并发执行时,CPU中的线程调度器会给每个线程分配一个时间片,当某个线程在时间片内仍没执行完,那程序计数器就得记录当前线程下一次被分配时间片执行时的下一条jvm指令的执行地址。
有什么需要注意的点?
  • 线程私有;
  • 不会存在内存溢出(⚠ 程序计数器是JVM中一个不会出现 OutOfMemoryError 的内存区域)
  • 它的生命周期随着线程的创建而创建,随着线程的结束而死亡;
  • Java中把CPU中的寄存器当作了“程序计数器”,因为寄存器是CPU中读取速度快的单元;

2️⃣ 虚拟机栈

它是个什么?

每个线程运行时所需要的内存,称为“虚拟机栈”。所有的 Java 方法调用都是通过栈来实现的(也需要和其他运行时数据区域比如程序计数器配合)。

每一个线程运行时需要给每一个线程划分一块内存空间,那虚拟机栈就是每一个线程运行时所需要的内存空间。一个线程就有一个虚拟机栈,多个线程就有多个栈。

方法调用的数据需要通过栈进行传递,每一次方法调用都会有一个对应的栈帧被压入栈中,每一个方法调用结束后,都会有一个栈帧被弹出。

每个栈由一个个栈帧(Frame)组成,对应着每次方法调用时所占用的内存。每个栈帧内部都拥有:局部变量表、操作数栈、动态链接、方法返回地址。栈顶部的,即正在被执行的方法,叫活动栈帧。

它有什么用?

栈用来执行所有方法,并返回结果。

什么情况下会栈内存溢出?
  • 栈帧过多导致栈内存溢出。如递归调用,没有递归出口,当线程请求栈的深度超过当前 Java 虚拟机栈的大深度的时候,就抛出 StackOverFlowError 错误;
  • 栈帧过大导致栈内存溢出。如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常;
有什么需要注意的点?
  1. 一个方法被调用时所占用的内存就是一个栈帧,方法中有方法参数,局部变量,返回地址等这些信息都是要占用内存的。所以每个方法执行时,需要预先把内存分配好。
有没有试过线程诊断?(Linux环境下)

shell

相关文章