【JVM】Java的内存模型(JMM)!

2023-09-15 16:31:29

一、运行时数据区域划分

JVM虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。

  • JDK 1.8分为:线程共享Heap堆区、Method Area方法区)、线程私有(虚拟机栈、本地方法栈、程序计数器)
  • JDK 1.8分为:线程共享Heap堆区MetaSpace 元空间)、线程私有虚拟机栈本地方法栈程序计数器

 

二、JVM中程序计数器(Program Counter Register)

是一块非常小的内存区域,它的作用是记录当前线程执行的字节码指令的地址。在Java虚拟机中,每个线程都有自己独立的程序计数器,因此多线程之间执行的程序计数器互不干扰。

程序计数器主要有如下两个作用

  • 线程切换恢复:当线程被切换时,程序计数器可以帮助线程恢复到之前执行的位置,从而继续执行。

  • 字节码指令定位:程序计数器可以帮助JVM在多线程环境下准确地定位到每个线程正在执行的指令,从而保证线程间的切换和协作的正确性。

  • 异常情况 

程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它随着线程的创建而创建,随着线程的结束而死亡。

三、Java 虚拟机栈(VM Stack) 

Java 虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有局部变量表操作数栈动态链接方法出口信息。 

 操作数栈:主要用于保存计算过程中的中间结果,同时作为计算过程中变量临时的存储空间。

当一个方法开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令向操作数栈中写入和提取内容,也就是出栈和入栈操作。

例如整数加法(2+3)的字节码指令iadd,这条指令在运行的时候要求操作数栈中最接近栈顶的两个元素已经存入了int类型的数据,当执行这个指令时,会把这两个int值出栈并相加,然后将相加的结果重新入栈。

每一次方法调用都会有一个对应的栈帧被压入 VM Stack虚拟机栈,每一个方法调用结束后,代表该方法的栈帧会从VM Stack虚拟机栈中弹出。

在活动线程中, 只有位于栈顶的帧才是有效的, 称为当前活动栈帧,代表正在执行的当前方法。
操在JVM执行引擎运行时, 所有指令都只能针对当前活动栈帧进行操作。虚拟机栈通过 poppush的方式,对每个方法对应的活动栈帧进行运算处理,方法正常执行结束,肯定会跳转到另一个栈帧上。

  • 异常情况

Java 虚拟机栈会出现两种错误:StackOverFlowError OutOfMemoryError

  • StackOverFlowError 当线程请求栈的深度超过 JVM虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。
  • OutOfMemoryError JVM的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

四、本地方法栈(Native Method Stack) 

native关键字修饰的本地方法被执行的时候,在本地方法栈中也会创建一个栈帧,用于存放该native本地方法的局部变量表、操作数栈、动态链接、方法出口信息。方法执行完毕后,相应的栈帧也会出栈并释放内存空间。

  • 异常情况

也会出现 StackOverFlowErrorOutOfMemoryError两种错误。 

五、堆(Heap) 

堆的作用是存放对象实例和数组

从结构上来分,可以分为新生代和老年代。而新生代又可以分为Eden 空间、From Survivor 空间(s0)、To Survivor 空间(s1)。 所有新生成的对象首先都是放在新生代的。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来的对象,和从前一个Survivor复制过来的对象,而复制到老年代的只有从第一个Survivor区过来的对象。而且,Survivor区总有一个是空的。

(1)新生代和老年代

 

(2)创建对象的内存分配

创建一个新对象,在堆中的分配内存。

大部分情况下,对象会在 Eden生成,当 Eden 区装填满的时候,会触发 Young Garbage Collection,即 YGC垃圾回收的时候,在 Eden 区实现清除策略,没有被引用的对象则直接回收。

依然存活的对象会被移送到 SurvivorSurvivor 区分为 s0 s1 两块内存区域。每次 YGC的时候,它们将存活的对象复制到未使用的Survivor 空间(s0s1),然后将当前正在使用的空间完全清除,交换两块空间的使用状态。每次交换时,对象的年龄会加+1

如果 YGC 要移送的对象大于 Survivor 区容量的上限,则直接移交给老年代。一个对象也不可能永远呆在新生代,在 JVM 中 一个对象从新生代晋升到老年代的阈值默认值是 15,可以在 Survivor区交换 14 次之后,晋升至老年代。

  • 异常情况

如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常

堆区最容易出现的就是 OutOfMemoryError错误,这种错误的表现形式会有以下两种:

  1. OutOfMemoryError: GC Overhead Limit Exceeded JVM花太多时间执行垃圾回收,并且只能回收很少的堆空间时,就会发生此错误。
  2. OutOfMemoryError: Java heap space假如在创建新的对象时, 堆内存中的空间不足以存放新创建的对象, 就会引发此错误。

六、元空间(Meta Space)

 用于存放类信息常量静态变量JIT即时编译器编译后的机器代码等数据等。例如:java.lang.Object类的元信息、Integer.MAX_VALUE常量等。

七、字符串常量池 

(1)String的两种创建方式

  • 第一种方式是在常量池中获取字符串对象;
  • 第二种方式是直接在堆内存空间创建一个新的字符串对象;

(2)Stringintern()方法

  • 检查指定字符串在常量池中是否存在?如果存在,则返回地址,如果不存在,则在常量池中创建
更多推荐

提前放电避雷针防雷综合应用方案

放电避雷针是一种利用电离空气提前放电的避雷装置,可以有效地保护建筑物、设备和人员免受雷电的危害。放电避雷针有多种类型,根据其放电机理和结构特点,可以分为以下几类:地凯科技预放电避雷针:这种避雷针利用雷云产生的空间电场强度,预先使周围的空气电离,空气离子在空间电场的作用下加速接近雷云,从而使迎面先导大大提前与雷云的下行先

Raft协议

前言最近在系统的实战springcloud,在学习nacos过程,我们知道nacos的底层用到了Raft协议。在Raft协议之前是一个paxos的协议,但是这个协议有点复杂,于是Stanford的两位教授决定设计一种较简单的一致性算法。参考自Raft动态演示网站我们一起来学习一下Raft协议。Raft前置概念term:

【CSS3】CSS3 3D 转换 ④ ( 3D 旋转 rotate3d | rotate3d 语法 | rotate3d 自定义轴旋转 | 元素旋转方向 - 左手准则 | 代码示例 )

文章目录一、3D旋转rotate3d1、rotate3d语法2、rotate3d自定义轴旋转3、元素旋转方向-左手准则二、代码示例1、代码示例2、执行结果一、3D旋转rotate3d3D旋转指的是在三维空间坐标系中,绕X轴,Y轴,Z轴进行旋转,同时还可以绕自定义轴进行旋转;2D旋转只能以某个点为中心进行旋转,3D旋转可

eSIM简介

翻译自eSIMeSIMeSIM被称为许多不同的名字。有人说嵌入式SIM,有人说电子SIM和其他的说eSIM。在行业标准最终确定并在该地区广泛采用之前,还会有其他名称出现。无论我们称之为什么,此SIM的基本思想是将SIM(UICC)作为用户设备(例如,M2M终端,移动电话等)的不可移除/固定组件分发。设备制造商对SIM卡

可以创业,也可以副业的网上长期挣钱的项目

在这个飞速发展的互联网时代,越来越多的人开始尝试在网上创业或者寻找一份可持续的副业来增加收入。不过在网上赚钱的难度是比较大的,不是轻易就能做到的,所以不付出一番努力,没有悟性和执行力,那么是很难做好的,那么有哪些靠谱的互联网长期赚钱项目呢?分享几个适合互联网创业或者副业的长期挣钱项目,希望能够对大家有所帮助。博客很多人

代码随想录二刷Day 15

102.BinaryTreeLevelOrderTraversalvector<int>()itisbasicallyconstructorofstd::vectorclassandwillcreateanewemptyvector.Youcanalsomentionthesizeofrequiredvectorinb

如何低成本、低门槛开发全屋智能系统?

近期,某个科技通讯巨头豪掷15亿重金,准备成立房地产公司以大力推动全屋智能的发展。从大部分科技公司频频押注全屋智能领域来看,全屋智能已然成为智能家居第一大发展趋势,是资本市场的重头戏。但全屋智能并不好做,不仅在于智能化水平跟不上消费端真实需求,而且连接、交互、生态这三道枷锁(即智能单品连接协议不统一、家庭联动场景互相割

彻底解决ruoyi分页后总数错误的问题

问题描述最近时不时的发现用户列表出来的数据只有24条,但是总记录数却有58条,很奇怪。各种百度查询,都是什么修改查询分页改代码,尝试后发现还是没有效果,经过各种验证发现就是SQL语句错误。如果非要说是SQL语句没有问题,查询出来的数据是正确的,如果基于这个事实去讲那确实没有错,错的是你建表的字段类型不一致,这是本质错误

Linux- dup()系统调用

dup()dup()(duplicate)是一个UNIX系统调用,用于创建一个现有文件描述符的副本。这个新的文件描述符与原始文件描述符在许多方面是相同的:它们共享同一个文件表项,这意味着它们指向相同的文件、套接字或其他I/O通道,并共享相同的文件偏移量、访问权限等。函数原型dup()函数的原型如下:#include<u

花了一周时间,更新了下软考云题库Web版

花了一周时间,更新了下软考云题库Web版,体验地址和体验账户在文章最后。想体验的直接翻到最后。软考云题库的Web版的由来之前,有朋友提出在小程序中刷题不太方便,希望能在电脑上进行题目练习。于是,我们着手开发了软考云题库的Web版,以满足这一需求。在这个项目中,我们采用了一套完整的技术方案,包括了SpringBoot2.

python生成PDF报告

前言最近接到了一个需求-将项目下的样本信息汇总并以PDF的形式展示出来,第一次接到这种PDF的操作的功能,还是有点慌的,还好找到了reportlab这个包,可以定制化向PDF写内容!让我们由简入深进行讲解一、reportlab是什么?reportlab是久经考验的,超强大的开源引擎,用于创建复杂的,数据驱动的PDF文档

热文推荐