JVM内存结构

img

运行时数据区

内存是非常重要的系统资源,是硬盘和CPU的中间仓库及桥梁,承载着操作系统和应用程序的实时运行。JVM内存布局规定了Java在运行过程中内存申请、分配、管理的策略,保证了JVM的高效稳定运行。不同的JVM对于内存的划分方式和管理机制存在着部分差异。

下图是JVM整体架构,中间部分就是Java虚拟机定义的各种运行时数据区域。

运行时数据区包含方法区、本地方法栈、虚拟机栈、程序计数器、堆

jvm-framework

  • 线程私有:程序计数器、虚拟机栈、本地方法区
  • 线程共享:堆、方法区、堆外内存(Java7的永久代或JDK8的元空间、代码缓存)

一、程序计数器

程序计数器也叫PC寄存器,抽象与CPU的寄存器,它的作用是记住当前线程执行的下一条指令的地址,以便线程再被调用时来找到该指令的地址进行执行。

  • 程序计数器是线程私有的
  • 程序计数器会随着线程的创建而创建,随着线程的销毁而销毁
  • 每个线程都有自己独有的程序计数器
  • 他是唯一一个在JVM中不会内存溢出的区域

二、虚拟机栈

Java虚拟机栈,早起也叫Java栈。每个线程在创建的时候都会创建一个虚拟机栈,内部保存的是一个个栈帧,对应着一次次Java方法调用,是线程私有的,生命周期与线程一致。

作用:虚拟机栈主要处理Java程序的运行,因为栈中保存的是一个个栈帧,每个栈帧对应一个方法调用,所以虚拟机栈主要保存栈帧(方法)的局部变量、部分结果,并处理栈帧的地调用与返回

特点:

  • 访问效率仅次于程序计数器
  • JVM对虚拟机栈的直接访问只有两个,每个方法被调用,伴随着入栈(压栈),以及方法结束出栈

2.4 栈帧的内部结构

每个栈帧内部都存储着:

  • 局部变量表
  • 操作数栈
  • 动态链接:指向运行时常量池的方法引用
  • 方法返回地址:方法正常退出或异常退出的地址
  • 一些附加信息

jvm-stack-frame

2.4.1 局部变量表

  • 局部变量表主要存储方法参数和方法内部定义的参数,包括编译器可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、int、float、long、double)对象引用(reference类型),对象引用并不等同于对象本身,可能是一个指向对象原始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此相关的位置和returnAddress**类型。
  • 因为局部变量表存储在线程的栈中,是线程私有的数据,因此不会有线程安全问题。
  • 方法嵌套调用的次数有栈的大小决定,一般栈越大,方法嵌套调用的次数越多。

2.4.2 操作数栈

  • 每个独立的栈帧中除了包括局部变量表之外,还包括一个后进先出的操作数栈,也可以称之为表达式栈
  • 操作数栈,在方法执行的过程中,根据字节码指令,往操作数栈中写入数据或提取数据,即入栈(push),出栈(pop)
  • 某些字节码指令将值压入操作数栈,其他字节码指令将操作数取出栈。使用他们后在把结果压入栈。比如,执行赋值、交换、求和等操作

四、堆内存

4.1 内存划分

对应大多数Java应用,堆内存是内存结构中分配内存最多的一个。它内部存放了对象的实例,并被所有线程共享。几乎所有的对象以及数据都在这里进行分配内存。

为了高效的垃圾回收,虚拟机把堆内存逻辑上划分为3块区域(分区域的唯一理由是提高GC的效率

  • 新生代(年轻代):新对象和一些没有达到一定年龄的对象都在新生代
  • 老年代(养老区):当一些对象达到年龄阈值时,会被提升到老年代,老年代比新生代的内存空间更大,因为都是长期需要使用的对象
  • 元空间(JDK1.8之前叫永久代):方法中的操作临时对象等。JDK1.8之前使用JVM内存,1.8之后直接使用物理内存
年轻代

年轻代是所有新对象创建的地方。当填充年轻代是,执行垃圾收集。这种垃圾收集成为Minor GC。年轻一代被分为三个部分——伊甸园(Eden Memory)和两个幸存区(Survivor Memory,被称为from/to或s0/s1),默认比例是8:1:1

  • 大多数新创建的对象都位于Eden内存空间中
  • 当Eden空间被对象填充时,执行Minor GC,并将所有幸存者对象移动到一个幸存者空间中
  • Minor GC检查幸存者对象,并将他们移动到另一个幸存者空间。所以每次,幸存者空间总是空的
  • 经过多次GC循环后存活下来的对象会被移动到老年代。通常,这是通过设置年轻一袋的年龄阈值来实现的,然后他们才有资格提升到老一代
老年代

老年代指的是经过多次垃圾回收并幸存下来且达到年龄阈值的对象,会将对象的级别提升到老年区。当老年区内存满后会进行垃圾回收(Major GC),通常需要更长的时间。

大对象会直接进入老年代(大对象指的是使用连续内存空间的对象)。这样做的目的是防止对象在Eden和Survivor进行大量的内存拷贝。

元空间

4.5 GC垃圾回收简介

Minor GC、Major GC、FullGC

JVM在进行内存回收时,并不是每次都对堆(新生代、老年代;方法区)进行回收,大部分回收都是指新生代。

最后修改:2023 年 04 月 04 日
如果觉得我的文章对你有用,请随意赞赏