面试官:JVM调优,主要针对是哪一个区域?JVM内存结构是怎样的?

作为一个Java程序员,在日常的开发中,不必像C/C++程序员那样,为每一个内存的分配而操心,JVM会替我们进行自动的内存分配和回收,方便我们开发。但是一旦发生内存泄漏或者内存溢出,如果对Java内存结构不清楚,那将会是一件非常麻烦的事情!本文笔者将为大家详解Java内存结构。

面试tips

  1. 聊聊Java内存结构?都有哪些组成部分?哪些是线程共享?哪些是线程私有?

  2. 我们通常说的JVM调优,主要针对是哪一个区域?这个区域中那一块是最大的?主要用于存放什么内容?

  3. Java虚拟机栈存储的内容是什么?

  4. 程序计数器的作用是什么?当内存不足时,程序计数器会发生OOM吗?

  5. 聊聊你对方法区的看法?在不同JDK版本中,方法区的演进过程是什么?

你是否对这些问题都了如指掌?看完本文相信你心中就会有答案!

JVM架构

JVM的平台无关性

jvm与操作系统

  1. 计算机的CPU、内存、显卡等等属于硬件

  2. 常用的MacOs、Windows、Linux属于计算机的操作系统

  3. 而Java的虚拟机,也就是JVM是运行在操作系统之上的,与硬件没有直接联系,JVM也是Java能够跨平台的根本原因。

JVM架构

image-20240630174946980

1. Class Loader 类加载器

类加载器的作用是加载类文件到内存,比如编写一个 HelloWord.java 文件,然后通过 javac 编译成 class 文件,那怎么才能加载到内存中被执行呢?答案就是 Class Loader。当然,不是任何 .class 文件就能被加载的,Class Loader 加载的 class 文件是有格式要求

2. Execution Engine 执行引擎

Class Loader 只负责加载,只要符合文件结构就加载,至于说能不能运行,则不是它负责的,那是由 Execution Engine 负责的。执行引擎也叫做解释器 (Interpreter),负责解释命令,提交操作系统执行

3. Native Interface 本地接口

本地接口的作用是融合不同的编程语言为 Java 所用,它的初衷是融合 C/C++ 程序,Java 诞生的时候是 C/C++ 横行的时候,于是就在内存中专门开辟了一块区域处理标记为 native 的代码

4. Runtime data area 运行时数据区

运行时数据区是整个 JVM 的重点。我们所有写的程序都被加载到这里,之后才开始运行,下面会重点讲解运行时数据区。

JVM执行流程

当然不同的VM的具体实现细节也不是不一样的,现在使用的比较多的JDK8版本就是Sun HotSpot VM与BEA JRockit VM合并之后开发出的JDK版本。

下面就是一个Java文件加载并执行的流程

JVM架构

运行时数据区

运行时数据区是JVM中最为重要的部分。也是我们在调优时需要重点关注的区域。

运行时数据区分为:程序计数器Java虚拟机栈本地方法栈Java堆区方法区

其中

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

  • 线程共享:堆、方法区, 堆外内存(Java7的永久代或JDK8的元空间、直接内存)

JDK 1.8 和之前的版本略有不同,我们这里以 JDK 1.7 和 JDK 1.8 这两个版本为例介绍。

JDK 1.7

java-runtime-data-areas-jdk1.7

JDK 1.8

java-runtime-data-areas-jdk1.8

程序计数器

程序计数寄存器(Program Counter Register),Register 的命名源于 CPU 的寄存器,寄存器存储指令相关的线程信息,CPU 只有把数据装载到寄存器才能够运行。它是一块很小的内存空间,几乎可以忽略不计。也是运行速度最快的存储区域

  1. JVM 中的 PC 寄存器是对物理 PC 寄存器的一种抽象模拟。可以看作是当前线程所执行的字节码的行号指示器。解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。

  2. 由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器

  3. 任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。如果当前线程正在执行的是 Java 方法,程序计数器记录的是 JVM 字节码指令地址,如果是执行 native 方法,则是未指定值(undefined)

  4. 程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它的生命周期与线程保持一致。

jvm-pc-counter

Java虚拟机栈

每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次 Java 方法调用,是线程私有的,生命周期和线程一致。

1、栈的内部结构

每个栈帧(Stack Frame)中存储着:

  • 局部变量表(Local Variables):主要存放了编译期可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)

  • 操作数栈(Operand Stack):主要用于存放方法执行过程中产生的中间计算结果。另外,计算过程中产生的临时变量也会放在操作数栈中。如果被调用的方法带有返回值的话,其返回值将会被压入当前栈帧的操作数栈中

  • 动态链接(Dynamic Linking):指向运行时常量池的方法引用。Class 文件的常量池里保存有大量的符号引用比如方法引用的符号引用,当一个方法要调用其他方法,需要将常量池中指向方法的符号引用转化为其在内存地址中的直接引用。这个过程也被称为 动态连接

  • 方法返回地址(Return Address):方法正常退出或异常退出的地址

PS: 局部变量表中的变量也是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收

img

2、栈的执行流程

  • JVM 直接对虚拟机栈的操作只有两个:方法调用入栈,方法执行结束出栈

  • 在线程中,同一时间只会有一个活动的栈帧,即(栈顶栈帧)是有效的,这个栈帧被称为当前栈帧(Current Frame),与当前栈帧对应的方法就是当前方法(Current Method),定义这个方法的类就是当前类(Current Class)

  • 如果在该方法中调用了其他方法,对应的新的栈帧会被创建出来,放在栈的顶端,称为新的当前栈帧

  • 不同线程中所包含的栈帧是不允许相互引用的,即不可能在一个栈帧中引用另外一个线程的栈帧

jvm-stack-frame

3、栈的异常

  • StackOverFlowError 若栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候,就抛出 StackOverFlowError 错误。

  • OutOfMemoryError 如果栈的内存大小可以动态扩展, 如果虚拟机在动态扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

本地方法栈

本地方法栈和Java虚拟机栈所发挥的作用非常相似

  • 二者区别在于: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务

  • 本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。

  • 方法执行完毕后相应的栈帧也会出栈并释放内存空间,也会出现 StackOverFlowError 和 OutOfMemoryError 两种异常。

  • 在 Hotspot JVM 中,直接将本地方法栈和虚拟机栈合二为一

Java堆区

栈是运行时的单位,而堆是存储的单位

Java 堆是 Java 虚拟机管理的内存中最大的一块,被所有线程共享

PS:关于Java堆有很多细节可以深挖,例如堆的分代和对象的创建和回收等,后续我还会专门开一篇文章展开讲

1、堆的存储内容

此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数据都在这里分配内存。成员变量名和值存储于堆中,其生命周期和对象的是一致的。

Java 世界中“几乎”所有的对象都在堆中分配,但是,随着 JIT 编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。从 JDK 1.7 开始已经默认开启逃逸分析,如果某些方法中的对象引用没有被返回或者未被外面使用(也就是未逃逸出去),那么对象可以直接在栈上分配内存。

2、堆的分区和垃圾回收

为了进行高效的垃圾回收,虚拟机把堆内存逻辑上划分成三块区域(分代的唯一理由就是优化 GC 性能):

  • 新生带(年轻代):新对象和没达到一定年龄的对象都在新生代

  • 老年代(养老区):被长时间使用的对象,老年代的内存空间应该要比年轻代更大

  • 元空间(JDK1.8 之前叫永久代):一些方法中的操作临时对象等,JDK1.8 之前是占用 JVM 内存,JDK1.8 之后直接使用物理内存

img

3、堆出现的异常

堆这里最容易出现的就是 OutOfMemoryError 错误,比如:

  • java.lang.OutOfMemoryError: GC Overhead Limit Exceeded:当 JVM 花太多时间执行垃圾回收并且只能回收很少的堆空间时,就会发生此错误。

  • java.lang.OutOfMemoryError: Java heap space :假如在创建新的对象时, 堆内存中的空间不足以存放新创建的对象, 就会引发此错误。(和配置的最大堆内存有关,且受制于物理内存大小。最大堆内存可通过-Xmx参数配置,若没有特别配置,将会使用默认值,详见:Default Java 8 max heap sizeopen in new window)

方法区

方法区属于是 JVM 运行时数据区域的一块逻辑区域,是各个线程共享的内存区域

1、方法区和永久代以及元空间是什么关系呢?

方法区和永久代以及元空间的关系很像 Java 中接口和类的关系,类实现了接口,这里的类就可以看作是永久代和元空间,接口可以看作是方法区,也就是说永久代以及元空间是 HotSpot 虚拟机对虚拟机规范中方法区的两种实现方式。并且,永久代是 JDK 1.8 之前的方法区实现,JDK 1.8 及以后方法区的实现变成了元空间。

method-area-implementation

2、方法区的存储内容

当虚拟机要使用一个类时,它需要读取并解析 Class 文件获取相关信息,再将信息存入到方法区。方法区会存储已被虚拟机加载的 类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据。在加载类和结构到虚拟机后,就会创建对应的运行时常量池

运行时常量池(Runtime Constant Pool)是虚拟机规范中是方法区的一部分,在加载类和结构到虚拟机后,就会创建对应的运行时常量池;而字符串常量池是这个过程中常量字符串的存放位置。所以从这个角度,字符串常量池属于虚拟机规范中的方法区,它是一个逻辑上的概念;而堆区,永久代以及元空间是实际的存放位置。

3、方法区在 JDK6、7、8中的演进细节

method-area-jdk1.6

method-area-jdk1.7

文章转载自:程序员世杰

原文链接:https://www.cnblogs.com/xieshijie/p/18281083

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/772581.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【情绪ABC理论】你为什么生气?清理一下情绪垃圾吧!

心理学有一个著名的情绪ABC理论,认为人的情绪并不是由事件本身引起的,而是由对事件的看法所导致,情绪的困扰某种程度与我们的不合理信念有关。在无法改变事物本身时,转变自己的认识有助于保持阳光心情。 什么是ABC法则&#xff1…

2024最全前端面试系列(计算机网络)(非科班出身最薄弱的环节)

2020最全前端面试系列(CSS) 2020最全前端面试系列(VUE) 2020最全前端面试系列(浏览器原理) 2020最全前端面试系列(数据结构) 常见状态码 | | 类别 | 原因短语 | | — | — | —…

申请SSL证书 SSL是如何保护网站安全的

随着互联网的不断发展,网络安全问题日益凸显,特别是在数据传输和存储方面。为了保护网站和用户的数据安全,SSL(安全套接层)技术应运而生,成为了保护网站安全的重要工具。本文将详细介绍SSL如何保护网站安全…

2024-07-04 base SAS programming学习笔记8(HTML)

当使用ODS来进行结果或数据集输出的时候,可以同时设置多个ODS 命令,同时输出到多个不同的文件。使用_ALL_ 表示关闭所有的ODS输出窗口,比如: ods html file(body)"html-file-pathname"; ods html file"pdf-file-pa…

React、JSX简介、渲染列表、基础和复杂的条件渲染

目录 一、简介 1、搭建环境 2、回到项目(VScode) 3、项目核心渲染路径 4、网站资料(启动项目的方法) 二、JSX 三、实现渲染列表 四、实现条件渲染 五、实现复杂条件渲染 一、简介 1、搭建环境 npx creat-react-app reac…

【 VIPKID-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞 …

Soildwoker学习(特征学习4)

本节学习内容: 1、异性孔向导 2、螺纹孔的选择 M6 六角圆柱头螺钉 M6 螺纹孔 3、线性阵列 4、基准轴 5、镜像 特征镜像 实体镜像

Swagger php注解常用语法梳理

Swagger php注解常用语法梳理 快速编写你的 RESTFUL API 接口文档工具,通过注释定义接口和模型,可以和代码文件放置一起,也可以单独文件存放。 Swagger 优势 通过代码注解定义文档,更容易保持代码文档的一致性模型复用&#xff0…

Spring Boot中使用SpringEvent组件

Spring的事件机制是基于观察者模式的实现,主要由以下三个部分组成: 事件(Event):事件是应用中发生的重要事情,通常是一个继承自ApplicationEvent的类。 事件发布器(Publisher)&…

ubuntu使用官方deb文件安装指定版本cuda失败,总是装成最新版

之前安装过最新版的cuda,之后想换用旧版,但是按照官网的说明,sudo apt-get -y install cuda后总是装成最新版的。 解决方法: 最后一步使用sudo apt-get -y install cuda-x-x,直接指定你要安装的cuda的版本号。

python作业一

1. #A. num int(input("请输入要打印的层数:")) for n in range(1, num1):s ""for i in range(1, n1):s f"{i}" " "print(s)#B. num int(input("请输入要打印的层数:")) for i in range(num1, 0, -1):s" "f…

springcloud+vue项目,controller层接口返回json数据,前端可以接收到数据,但浏览器“F12-->网络-->响应“显示为空的问题处理

1.显示为空的场景 SharetekR(access_tokeneyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJQQzoxODA1ODA4ODc1MjUwMTIyNzUyIiwicm5TdHIiOiJrZEoxV05CV3NBSUdYb05TbktSU3kzOGNuSnk3c3FRTSIsInVzZXJJZCI6MTgwNTgwODg3NTI1MDEyMjc1MiwidXNlck5h…

分布式数据库HBase:从零开始了解列式存储

在接触过大量的传统关系型数据库后你可能会有一些新的问题: 无法整理成表格的海量数据该如何储存? 在数据非常稀疏的情况下也必须将数据存储成关系型数据库吗? 除了关系型数据库我们是否还有别的选择以应对Web2.0时代的海量数据? 如果你也曾经想到过这些问题, 那么HBase将是…

25届最近5年华北电力大学自动化考研院校分析

华北电力大学(北京保定) 目录 一、学校学院专业简介 二、考试科目指定教材 三、近5年考研分数情况 四、近5年招生录取情况 五、最新一年分数段图表 六、初试大纲复试大纲 七、学费&奖学金&就业方向 一、学校学院专业简介 二、考试科目指…

【C语言】刷题笔记 Day2

【笔记】 【1】局部变量不初始化,默认放的随机值。 1 int n0; 2 scanf("%d",&n); //13.141 【2】这里虽然输入的是一个浮点数,但是只取整数部分。 【3】3.156e7 表示的是3.156*10的7次方。 【4】多组输入,保存和不保存…

关于Wav2Lip配置实现

模型介绍 Wav2Lip是一种先进的深度学习模型,旨在将音频波形直接转换为面部动画,尤其关注于唇部动作的生成与同步。这一技术的核心在于其能够利用输入的语音信号,生成与之高度匹配的嘴唇动作,从而实现逼真的语音驱动数字人物动画效…

docker初始化运行mysql容器时自动导入数据库存储过程问题

问题:用navicat导出的数据库脚本,在docker初始化运行mysql容器时,导入到存储过程时出错。 ERROR 1064 (42000) at line 2452: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for t…

DataWhale-吃瓜教程学习笔记 (六)

学习视频**:第4章-决策树_哔哩哔哩_bilibili 西瓜书对应章节: 第五章 5.1;5.2;5.3 文章目录 MP 神经元- 感知机模型 (分类模型)-- 损失函数定义--- 感知机学习算法 - 随机梯度下降法 - 神经网络需要解决的问…

2024年显著性检测部分论文及代码汇总(3)

ICML Size-invariance Matters: Rethinking Metrics and Losses for Imbalanced Multi-object Salient Object Detection code Abstacrt:本文探讨了显著性检测中评价指标的尺寸不变性,尤其是当图像中存在多个大小不同的目标时。作者观察到,…