JVM调优:JVM运行时数据区详解

一、前言

  Java运行时数据区域划分,Java虚拟机在执行Java程序时,将其所管理的内存划分为不同的数据区域,每个区域都有特定的用途和创建销毁的时间。

  其中,有些区域在虚拟机进程启动时就存在,而有些区域则是随着用户线程的启动和结束而建立和销毁。这些数据区域包括程序计数器、虚拟机栈、本地方法栈、堆、方法区等,每个区域都有其自身的特点和作用。

  了解这些数据区域的使用方式和特点,可以更好地理解Java虚拟机的内存管理机制和运行原理。

  JVM的内存模型划分在java1.8与java1.8之前是不一样的,本文将对Java运行时数据区域划分进行详细的介绍,理解清楚了概念之后,才能更好的进行调优分析。

二、运行时数据区域划分

  首先提个概念,经常听人一会提到虚拟机的内存结构,一会又是运行时数据区域划分,其实就是一个意思。因为在《Java虚拟机规范》中用的是【运行时数据区】术语的,并没有内存结构这么一说法。内存结构只是听着更加贴切,更加形象,因此知道内存结构就是运行时数据区的意思就好了。

运行时数据区域划分

1. java1.8之前运行时数据区域划分

在这里插入图片描述
2. java1.8运行时数据区域划分
在这里插入图片描述
在Java中,JVM(Java虚拟机)的运行时数据区主要包括以下几个部分:

①. 程序计数器:

  1. 它是一块很小的内存空间,几乎可以忽略不计,也是运行速度最快的存储区域。

  2. 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。

  3. 为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存

  4. 它是程序控制流的指示器,分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器来完成。

  5. 它是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

②. Java虚拟机栈:

  1. 栈是运行时的单位,即栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。Java 虚拟机栈(Java Virtual Machine Stack),早期也叫 Java 栈。每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个栈帧,对应着一次方法的调用。
  2. Java虚拟机栈是线程私有的,主管Java程序的运行,它保存方法的局部变量(8种基本数据类型,对象的引用地址),部分结果,并参与方法的调用和返回。

  3. 每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

  2.1 栈帧的内部结构

  1. 局部变量表

    局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。

  2. 操作数栈

    栈最典型的一个应用就是用来对表达式求值。在一个线程执行方法的过程中,实际上就是不断执行语句的过程,而归根到底就是进行计算的过程。因此可以这么说,程序中的所有计算过程都是在借助于操作数栈来完成的。

  3. 动态链接

    因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。

  4. 方法返回地址

    当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。

③. 本地方法栈

  1. 与虚拟机栈所发挥的作用非常相似,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。本地方法栈也是线程私有的

  2. 允许被实现成固定或者是可动态扩展的内存大小;

  3. 内存溢出方面也是相同的,如果线程请求分配的栈容量超过本地方法栈允许的最大容量抛出 StackOverflowError;

  4. 本地方法是用 C 语言写的;它的具体做法是在Native Method Stack 中登记native方法,在Execution Engine执行时加载本地方法库。

④. Java堆:

  1. Java 堆区在 JVM 启动时的时候即被创建,其空间大小也就确定了,是Java虚拟机所管理的内存中最大的一块。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

  2. 堆内存的大小是可以调节:例如: -Xms:10m(堆起始大小) -Xmx:30m(堆最大内存大小)。一般情况可以将起始值和最大值设置为一致,这样会减少垃圾回收之后堆内存重新分配大小的次数,提高效率。

  3.《Java虚拟机规范》规定,堆可以处于物理上不连续的内存空间中,但逻辑上它应该被视为连续的;

  4. 所有的线程共享 Java 堆,在这里还可以划分线程私有的缓冲区;

  5. 在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除。所以堆是 GC(Garbage Collection,垃圾收集器)执行垃圾回收的重点区域。

  了解GC调优方面的知识点,可以参考我的文章 《JVM中常见的垃圾回收算法详解》 《JVM中的垃圾收集器详解》

java8之前与java8的区别主要是下面两个区域

⑤.方法区:
  又称为“永久代”(PermGen space),但在Java 8之后,这个区域被元空间(Metaspace)所替代。它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

  方法区,是一个被线程共享的内存区域。其中主要存储加载的类字节码、class/method/field 等元数据、static final 常量、static 变量、即时编译器编译后的代码等数据。另外,方法区包含了一个特殊的区域“运行时常量池”。

  Java虚拟机规范中明确说明:尽管所有的方法区在逻辑上是属于堆的一部分,但对HotSpotJVM 而言,方法区还有一个别名叫做 Non-Heap(非堆),目的就是要和堆分开。

⑥. 元空间:
  1. 在Java 1.8中,方法区(Method Area)被元空间(Metaspace)所取代。元空间是Java虚拟机规范对方法区的实现方式的一种要求。

  2. 元空间并不在虚拟机中,而是使用本地内存。默认情况下,元空间的大小仅受本地内存限制。

  3. 类元数据放入本地内存,字符串常量池和静态变量放入Java堆中,这样可以加载多少类的元数据就不再由MaxPermSize控制,而由系统的实际可用空间来决定。

三、堆内存模型

  1. java1.8之前堆内存模型
在这里插入图片描述
Young年轻区(代)
  Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,其中,Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Eden区间变满的时候,GC就会将存活的对象移到空闲的Survivor区间
中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到Tenured区间。

Tenured年老区
  Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young 复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。

Perm永久区
  Perm代主要保存class,method,filed对象,这部份的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError:PermGenspace的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。

Virtual区
  最大内存和初始内存的差值,就是Virtual区

2. java1.8堆内存模型
在这里插入图片描述

  由上图可以看出,jdk1.8的内存模型是由2部分组成,年轻代+年老代。
  年轻代:Eden + 2*Survivor
  年老代:OldGen
  在jdk1.8中变化最大的Perm区,用Metaspace(元数据空间)进行了替换。需要特别说明的是:Metaspace所占用的内存空间不是在虚拟机内部,而是在本地内存空间中,这也是与1.7的永久代最大的区别所在。

为什么要废弃1.7中的永久区?

官网给出了解释:http://openjdk.java.net/jeps/122

This is part of the JRockit and Hotspot convergence effort. 
JRockit customers do not need to configure the permanent generation (since JRockit does not have a permanent generation) 
and are accustomed to not configuring the permanent generation. 

移除永久代是为融合HotSpot JVMJRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代。

  现实使用中,由于永久代内存经常不够用或发生内存泄露,出现异常java.lang.OutOfMemoryError:PermGen。基于此,将永久区废弃,而改用元空间,改为了使用本地内存空间。

总结:
  充分理解Java虚拟机(JVM)的运行时数据区(也称为运行时内存区域)是进行JVM调优的基础。JVM的内存管理是其核心功能之一,而理解其内存布局和各个区域的功能,可以帮助我们更有效地进行性能调优。

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

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

相关文章

YOLOv9-20240507周更说明|更新MobileNetv4等多种轻量化主干

专栏地址:目前售价售价69.9,改进点70 专栏介绍:YOLOv9改进系列 | 包含深度学习最新创新,助力高效涨点!!! 本周已更新说明: ### ⭐⭐更新时间:2024/5/12⭐⭐ 1. YOLOv9…

企业网站HTTP网站业务被慢连接攻击了该怎么办

企业的网站建设中遇到网络攻击会出现哪些问题?一些中小型企业对于网络安全的认知不足,网站建设种类众多,电子商城类,小型游戏,支付类型,H5页面的网站,开发等等,如遇见网络攻击造成的…

ubuntu server 22.04.4 系统安装详细教程

本教程使用vmware workstation 17创建虚拟机进行安装演示,安装方式和真机安装没有区别。 1、下载镜像 下载ubuntu server版本系统镜像,官网下载地址:https://cn.ubuntu.com/download/server/step1 注意:自己下载时需要确认是否是…

ARP中间人

文章目录 ARP中间人ARP协议介绍使用kali进行ARP毒化使用kali进行ARP中间人使用kali进行ARP钓鱼ARP攻击防御ARP总结 ARP中间人 ARP协议介绍 维基百科ARP介绍 ARP(地址解析协议)在网络通信中扮演着至关重要的角色,它通过将网络层地址&#x…

运维基础(二)- 钉钉的使用

一、钉钉的介绍(来自百度百科) 免费沟通和协同的多端平台 帮助中国企业通过系统化的解决方案(微应用),全方位提升中国企业沟通和协同效率。 钉钉(Ding Talk) 是阿里巴巴打造的企业级智能移动…

Windows环境下代码文档生成工具Doxygen使用详细教程

背景 最近研究aom源码,发现编译需要依赖Doxygen工具,故此篇博客详细记录下Doxygen的安装和使用。 Doxygen Doxygen 是一个强大的源代码文档生成工具,它支持多种编程语言,能够直接从源代码中的注释提取文档,并生成多…

RabbitMQ中间件安装

消息队列 RabbitMQ yum -y update yum -y install epel-release erlang # 安装erlang erl -version # 判断是否安装成功根据官网的的表格判断自己用哪个版本的 RabbitMQ:https://www.rabbitmq.com/docs/which-erlang#r16b03 [rootiZuf6hqrs5cb2ccyuc9nqvZ ~]# er…

tomcat 设置JVM 参数

tomcat 启动的服务 设置jvm 设置的文件目录: /tomcat/bin/catalina.sh 添加设置参数: JAVA_OPTS“$JAVA_OPTS -server -Xms1024m -Xmx4096m -XX:MetaspaceSize1024m -XX:MaxMetaspaceSize2048m -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/data/se…

0510Goods的Maven项目

0510Goods的Maven项目包-CSDN博客 数据库字段 商品主页 修改页面 点击商品主页更改信息, 跳转到修改页面, 并保留初始信息。 商品类别最多选取三项,最少选取一项 添加界面 商品类别最多选取三项,最少选取一项

第三方组件element-ui

1、创建 选vue2 不要快照 vue2于vue3差异 vue2main。js import Vue from vue import App from ./App.vueVue.config.productionTip falsenew Vue({render: h > h(App), }).$mount(#app)vue3 main.js vue2不能有多个跟组件(div)

老胡的周刊(第141期)

老胡的信息周刊[1],记录这周我看到的有价值的信息,主要针对计算机领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 🎯 项目 koishi[2] 周刊群友推荐,创建跨平…

对博客系统基本功能进行自动化测试(Junit + Selenium)

环境搭建&#xff1a; 浏览器&#xff1a; 本次测试使用Chrome浏览器在jdk的bin目录下安装对应浏览器驱动&#xff08;尽量选择与浏览器版本相近的驱动&#xff09;chromedriver.storage.googleapis.com/index.htmlJunit依赖&#xff1a; <!-- https://mvnreposit…

【linux-IMX6ULL-RTC-IIC-SPI配置思路】

目录 1. RTC简介1.1 IMX6ULL中的RTC1.2 SNVS_LP中的SRTC配置流程1.3 程序实现 2. IIC通信协议2.1 IIC基础2.2 IIC通信协议2.2.1 IIC写时序2.2.2 IIC读时序 3. IIC通信的硬件框图及配置流程3.1 IMX6ULL的硬件IIC框图3.1 IIC配置流程3.2 硬件IIC代码实现 4. SPI通信4.1 SPI通信基…

【Python探索之旅】选择结构(条件语句)

文章目录 条件结构&#xff1a; 1.1 if单分支结构 1.2 if-else 多分支结构 1.3 if-elif 多重结构&#xff1a; 完结撒花​ 前言 Python条件语句是通过一条或多条语句的执行结果&#xff08;True或者False&#xff09;来决定执行的代码块。 Python提供了顺序、选择、循环三…

IP SSL怎么签发使用

IP证书的签发首先是需要有一个可供绑定的IP地址&#xff0c;作为常用数字证书之一&#xff0c;IP证书也因为其广泛的应用范围而深得用户的青睐和喜欢。 部署IP证书后&#xff0c;可以实现该IP地址的https访问&#xff0c;过程和域名证书相差不多。 IP证书和域名证书的区别 很…

针对关键 PuTTY 私钥恢复漏洞的 PoC 发布

安全研究人员针对广泛使用的 PuTTY SSH 和 Telnet 客户端中的一个关键漏洞发布了概念验证 (PoC) 漏洞利用。 该漏洞CVE-2024-31497允许攻击者恢复 PuTTY 版本 0.68 至 0.80 中使用 NIST P-521 椭圆曲线生成的私钥。 该漏洞源于 PuTTY在使用 P-521 曲线时偏向生成ECDSA随机数。…

算法课程笔记——自下而上树形DP

算法课程笔记——自下而上树形DP #include<bits/stdc.h>usingnamespacestd; constintN100005; intn,a[N]; longlongdp[N][2]; vector<int> e[N]; voiddfs(intu){for(autov:e[u]){dfs(v);dp[u][1]dp[v][0];dp[u][0]max(dp[v][0],dp[v][1]);}dp[u][1]a[u]; } intmain…

Vue中CSS动态样式绑定与注意事项

vue中css使用动态变量_vue css变量 动态-CSDN博客 需求&#xff1a; vue使用el-select&#xff0c;下拉选择值时‘输入框’的背景图片就改变为对应所选项的背景图 分析 &#xff1a; 每次下拉选择&#xff0c;值发生变化&#xff0c;背景图与值一一对应绑定&#xff0c;为动态…

[数据结构1.0]选择排序

鼠鼠前面的博客介绍过选择排序是常见的排序算法&#xff0c;选择排序有但不限于直接选择排序和堆排序&#xff01;那么鼠鼠今天浅谈一下选择排序&#xff01; 鼠鼠本博客用排升序来介绍选择排序&#xff01; 目录 1.直接选择排序 1.1.直接选择排序 1.2.直接选择排序特性 2…

FreeRTOS互斥量

目录 一、互斥量的概念 二、优先级翻转和优先级继承 1、优先级翻转 2、优先级继承 三、互斥量相关API 四、优先级实操 1、优先级翻转演示 1.1 CubeMX配置 1.2 代码实现 2、使用互斥量优化优先级翻转问题 2.1 CubeMX配置 2.2 代码实现 一、互斥量的概念 在多数情况…