美文网首页
jvm内存模型(运行时数据区)简介

jvm内存模型(运行时数据区)简介

作者: 脱轨的码农 | 来源:发表于2023-04-23 15:30 被阅读0次

jvm在java程序执行过程中会把内存划分为若干个区域,每个区域都有各自的用途以及它们的生命周期,下图讲的是JDK1.8版本

image.png

方法区(Method Area)

方法区在jdk1.8后被抛弃,jdk1.8后改成了元空间(Metaspace),方法区是线程共享区域,它用于存储虚拟机加载的类型信息,常量,静态变量,即时编译后代码缓存的数据等。

类型信息:类、接口、枚举、共有、私有、抽象类,继承的父类,静态方法,方法类型的修饰符等等

堆(Heap)

堆是虚拟机所管理的一块内存最大,是所有线程共享的内存区域,在虚拟机启动时创建,该内存区域几乎存放所有对象实例和数组。堆可以划分为不同的区域,不同的垃圾收集器堆划分的区域也是不一样的。

image.png

堆:堆是垃圾收集器管理的主要区域,因此被称为GC堆。堆被分为年轻代和老年代,年轻代分为Eden和Survivor,Eden占用内存最大,默认占比是8:1:1

非堆:永久代并不属于堆的一部分,是方法区。永久代在1.8之后废弃,替代成元空间,元空间和永久代的区别在于不在jvm,而是使用本地内存,所以大小会受本地内存限制。

新创建的对象首先会存放在年轻代Eden区,Eden区满了后会触发MinorGC,MinorGC用来清理年轻代垃圾,Eden区存活下来的对象会移动到S0区,S0区满后再次触发MinorGC,S0存活下来的对象移动到S1区,对象在Survivor区经过一次MinorGC生存下来年龄+1,经过多次MinorGC存活下来的对象超过一定年龄(默认15)会移动到Old Space老年代,大的对象直接进入老年代。

老年代区存满后会触发MajorGC,也就是我们说的Full GC,触发Full GC会停止(STW)所有线程去等待GC完成,为了提高性能,尽量减少Full GC的次数。

堆分代的作用就是针对不同对象的生命周期,存放在不同区域,从而减少扫描的时间,针对不同区域使用不同的GC算法进行回收,提高GC的回收效率,可以通过-Xms,-Xmx设置堆初始的内存最大值和最小值。
各种平台的优惠券(外卖、电影、电商、出行、景区)小程序--》猴哥探店

程序计数器(Program Counter Register)

在了解程序计数器前,先了解一下什么是寄存器?

寄存器是CPU内部的运行非常快的存储器,有如下作用:

1、作为CPU内部数据传输和处理的暂存器,CPU需要从内存中读取数据并进行运算,将运算结果再存回内存,这个过程需要寄存器作为数据传输和处理的暂存器,提高数据的传输和处理速度。

2、保存程序计数器,程序计数器是一个用于存储CPU即将要执行的指令地址的寄存器,CPU在执行的过程中需要不断地更新计数器的中的值,以便执行下一条要执行的指令。

3、保存CPU执行指令的状态信息

4、保存函数调用时返回的地址和参数,在函数调用时,需要将返回的地址保存在寄存器中,以便执行完函数返回正确的位置

程序计数器在jvm中占用非常小的内存空间,它可以看作是当前线程所执行的字节码行号指示器。而字节码指示器工作时就是通过改变这个程序计数器的值来确认下一条要执行的字节码指令。JVM的每个线程都有自己的程序计数器,各自线程计数器互不影响,独立存储。它的线程是私有的,在线程切换过程中,程序计数器也会被保护和恢复。程序计数器占用非常小的内存空间,因此它不会发生OutOfMemoryError异常。

程序计数器的作用:

1、字节码解释器工作时,通过改变计数器的值来选取下一条要执行的字节码指令。

2、在线程执行过程中,用于记录当前线程所执行的位置,以便在发生异常时,能够恢复程序的执行。

JVM的程序计数器常常被称为寄存器,当前线程通常与CPU中的寄存器类似,用于保存简单的数据和指针。程序计数器在JVM执行过程中扮演着类似寄存器的作用,用于记录当前线程的执行顺序和状态,通过改变计数器的值,实现线程执行过程中跳转不同的字节码指令。需要注意,jvm的程序计数器并不是CPU的寄存器,CPU的寄存器是一种硬件设备,位于CPU内部,而程序计数器位于JVM的一小块内存空间,是JVM实现的一部分。

虚拟机栈(Java Virtual Machine Stack)

栈和堆的区别

栈是运行单位,处理程序运行问题,堆是存储单位,处理存储问题。

虚拟机栈是运行时数据区的一部分,用于存储线程的执行状态,每个线程创建时都会创建一个虚拟机栈,在执行方法时都会创建一个栈帧(Stack Frame),用于存储局部变量、操作数栈、动态链接、方法返回地址等信息。每个栈帧对应的一个正在执行的方法,线程是私有的,它的生命周期与线程相同,每个方法被调用到执行完毕,就是栈帧在虚拟机入栈到出栈的一个过程,线程结束了,虚拟机栈随之销毁。

当我们方法被编译成字节码,通过程序计数器,虚拟机会一行行的执行命令,直到进入新的方法,虚拟机就会创建一个新的栈帧入栈,直到方法执行结束触发返回指令或者出现异常方法结束对应栈帧出栈,在编译过程需要的局部变量大小,需要多少栈帧,需要多大内存,在编译期间就已经确认。

image.png image.png

局部变量表

局部变量表是一个数组,用于存储方法参数和方法内的局部变量,包括三种数据类型:8大基本数据类型、引用类型、Return Address。

局部变量的容量大小在编译期间就已经确定,在运行期间不会改变。

操作数栈

每个栈帧都包含一个操作数栈,栈帧创建时,操作数栈是空的,并且操作数栈的深度在编译期间就已定义好,double或long(64位)占两个单位的栈深度,其他数据类型(32位)占一个单位栈深度。

作用:操作数栈用于接受方法参数和返回结果值

动态链接

每个栈帧内部都包含一个指向当前方法所在类型的运行时常量池的引用,是对当前方法实现的动态链接。一个方法要访问它的成员变量,需要通过符号引用来表示,动态链接的作用就是将这些符号引用的方法转换成实际方法的引用。

方法返回地址

方法返回地址分两种,一种是正常执行完的返回,另一种是出现异常(异常是未处理的)执行完的返回。

正常执行完的的场景下,当前栈帧需要调用调用者的局部变量表,操作数栈,正确的递增程序计数器等,将返回值压入调用者栈帧的操作数栈后,调用者继续正常执行。

正常完成和异常完成的区别:通过异常完成退出的不会给上层调用者产生返回值。

本地方法栈(Native Method Stacks)

本地方法栈和虚拟机栈类似,虚拟机栈是执行java方法服务(java 字节码),本地方法栈执行的Native方法服务,就是执行非java 语言的代码,本地方法可以动态扩容内存大小,本地方法会根据栈的深度溢出,或者扩展失败,分别跑出StackOverflowError和OutOfMemoryError异常。

各种平台的优惠券(外卖、电影、电商、出行、景区)小程序--》猴哥探店

相关文章

  • 线程安全之可见性问题

    Java内存模型 VS JVM运行时数据区 首先Java内存模型(JMM)和JVM运行时数据区并不是一个东西,许多...

  • JVM学习笔记

    JVM 注意:0、JVM运行时数据区和JVM内存模型不要搞混1、运行时数据区可以分为:堆、方法区、虚拟机栈、本地方...

  • 线程在JVM中的运行原理

    。线程在启动运行时,主要是在运行时数据区(JVM的内存模型),而JVM的运行时数据区主要包括堆,方法区,Java栈...

  • 类加载机制详解

    之前在介绍JVM内存模型的时候(参看:JVM内存模型),提到了在运行时数据区之前,有个Class Loader,这...

  • JVM内存模型

    一、JVM内存模型图解 JVM 运行时数据区 (JVM Runtime Area) 其实就是指 JVM 在运行期间...

  • JVM内存模型和JVM内存结构的区别

    JVM内存模型与内存结构不是同一个概念,JVM内存结构是从运行时数据区的结构角度描述的概念,而JVM内存模型是从主...

  • Java线程安全-可见性问题

    Java内存模型(JMM) 与 JVM运行时数据区 Java内存模型是《Java语言规范》中,描述对java语...

  • JVM——Java内存模型JMM

    一、JVM运行时数据区 二、Java内存模型 JCP定义了一种Java内存模型,以前是在JVM规范中,后来独立出来...

  • JVM内存分析

    JVM内存模型图JAVA虚拟机把管理的内存划分为几个不同的数据区。 JVM运行时数据区分类1. JVM栈 (Jav...

  • JVM内存模型

    JVM内存模型划分JVM内存模型分为 虚拟机栈、堆、方法区、程序技术器、本地方法栈五个部分。 1. 运行时数据区域...

网友评论

      本文标题:jvm内存模型(运行时数据区)简介

      本文链接:https://www.haomeiwen.com/subject/opcyjdtx.html