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的内存管理是其核心功能之一,而理解其内存布局和各个区域的功能,可以帮助我们更有效地进行性能调优。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CANape测量分析标定

CANape创建工程及标定 1 创建工程 1. 创建ape工程 打开CANape软件,创建新的ape工程 2.添加数据库文件 通过添加Device(确定信号源)的方式加载数据库文件 A2L:通过添加CCP、 XCP、VX1000的Device DBC:对总线报文检测 CAN CDD: 诊断功能 Diagnostic 如需导入MAP文件…

道格拉斯普克算法(DP)的点云轮廓线简化

1、背景介绍 由于点云无法精确刻画目标对象边缘信息,因此常规提取的边缘点直接相连所生成的轮廓线,锯齿现象显著,与真实情况相差甚远(图b所示)。 道格拉斯-普克(Douglas-Peuker)抽稀算法是用来对…

【数据库系统工程师】2024年5月考前最后冲刺指南

一、备考关键: 高效率的备考方式:多轮迭代学习 △ 基础阶段 △ 大面积撒网(60%) 略读-> 做题 -> 回顾 -> 精读 △ 积累阶段 △ 有针对性的突破(30%) 完成所有章节之后,进行真题测试&#x…

爬取深圳2024年链家二手房数据,共3000条数据(其他城市也可)

文章目录 专栏导读1.目标2.导入相关库3.获取每个二手房的链接4.获取每个链接中的相关数据5.保存数据6.数据展示 专栏导读 ✍ 作者简介:i阿极,CSDN 数据分析领域优质创作者,专注于分享python数据分析领域知识。 ✍ 本文录入于《python网络爬虫…

鲜活很有感染力的女生图片_活力满满有生命力女生图片

鲜活很有感染力的女生图片_活力满满有生命力女生图片

公有云Linux模拟UDP端口并抓包

目录 写在前面操作步骤服务端开启UDP端口并监听客户端连接Wireshark抓包查看 写在前面 关于具体的操作,请参考我的上一篇文章 公有云Linux模拟TCP三次挥手与四次握手(Wireshark抓包验证版) 在本文,仅介绍与上一篇不同的地方。 操…

R语言:GSEA分析

#安装软件包 > if (!requireNamespace("BiocManager", quietly TRUE)) install.packages("BiocManager") > BiocManager::install("limma") > BiocManager::install("org.Hs.eg.db") > BiocManager::install("…

【算法刨析】完全背包

完全背包与01背包的区别 01背包对于一个物品只能选择一次,但是完全背包可以选择任意次; 思路 和01背包类似,01背包我们只需要判断选或不选,完全背包也是如此,不同的是,对于这个物品我们在判断选后在增加一…

【送书福利第七期】你好!Java(文末送书)

文章目录 编辑推荐内容简介作者简介目录前言/序言 编辑推荐 适读人群 :程序员;相关院校师生 本书以轻松幽默的语言,从零开始介绍Java语言。书名来源于编程语言中最经典的Hello World程序,寓意带读者从入门到精通。 书中每章都设有总结与扩展…

vue3延迟加载(异步组件​)defineAsyncComponent

最简单用法 Index.vue: <script setup> import { onMounted, defineAsyncComponent } from vue import ./index.cssconst Child defineAsyncComponent(() > import(./Child.vue))onMounted(() > {}) </script><template><div class"m-home-w…

Linux学习笔记4

书接上文&#xff0c;我们上两篇在讲建立最小Linux系统时要创建的几个脚本&#xff0c;接下来我们继续说一下 建立最小系统之创建文件系统所需文件&#xff08;续&#xff09; 之后我们返回etc目录&#xff0c;再返回system目录&#xff0c;接着使用“cd lib”命令进入到lib …

现在做电商迟吗?那是你不知道今年黑马,视频号小店重磅来袭

大家好&#xff0c;我是电商笨笨熊 24年想做电商&#xff0c;还能不能做&#xff1f; 当然可以。 电商是一个长期的市场&#xff0c;只要用户有需求&#xff0c;那么电商就会一直存在&#xff1b; 尤其是近几年来无货源模式爆火&#xff0c;对于我们商家来说这种无需自备货…

flutter 使用Scrollbar 时出现 滚动条不置顶问题

Flutter 使用 CupertinoScrollbar 、Scrollbar 与 ListView.builder 结合使用时&#xff0c; 当把 ListView.builder 边距设置为 padding: const EdgeInsets.all(0) 的时候&#xff0c; Scrollbar 的滚动条不置顶。 如图&#xff1a;右侧边上的滚动条 解决方法&#xff1a; …

抖店的爆品,到底是选出来的还是推出来的?我的看法是......

我是王路飞。 做电商的&#xff0c;你要说你对爆品没有想法&#xff0c;那劝你不要做了。 有人认为做抖店&#xff0c;爆品都是选出来的&#xff0c;毕竟方向不对&#xff0c;努力白费。 也有人认为做抖店&#xff0c;爆品都是推出来的&#xff0c;再好的产品&#xff0c;达…

KNIME 报告扩展

文档对应的 KNIME AP 版本为 5.2 介绍 本指南介绍了 KNIME 报告扩展&#xff0c;并展示了如何创建简单和高级报告。 本指南更新于 2024/05/13&#xff0c;最新版请访问指北君网站 https://havef.fun/knime-cn/knime-doc/ KNIME 报告扩展允许您根据工作流程的结果创建静态报告。…

租赁小程序开发搭建支持时租日租月租

租赁小程序开发搭建支持时租日租月租 一款开源版的小程序&#xff0c;专为物品租赁服务设计&#xff0c;能满足客户在各种租赁场景中的需求。 该程序支持时租、日租、夜租等多种租赁方式&#xff0c;并配备了DIY页面和分销系统。用户可以通过平台轻松租赁商品&#xff0c;支付…

HTML与cgi程序的数据交互

1. Html通过ajax获取cgi返回的数据 function HtmlGetCgiData() {$.ajax({type: POST, //提交方法url: cgi-bin/wg67_key_in/wg67_key_in_reflush.cgi, //调用到的cgi程序data: "ajax", //发送的数据&#xff0c;不可缺失该项&#xff0c;不能为空&#xff08;空&…

[Linux][网络][协议技术][DNS][ICMP][ping][traceroute][NAT]详细讲解

目录 1.DNS1.DNS背景2.域名简介 2.ICMP协议1.ICMP功能2.ICMP两类报文 3.ping命令4.traceroute5.NAT技术1.NAT技术背景2.NAT IP转换过程3.静态地址NAT && 动态地址NAT4.网络地址端口转换NAPT5.NAT技术的缺陷6.NAT和代理服务器 6.总结1.数据链路层2.网络层3.传输层4.应用…

难以重现的 Bug如何处理

对很多测试人员&#xff08;尤其是对新手来说&#xff09;在工作过程中最不愿遇到的一件事情就是&#xff1a;在测试过 程中发现了一个问题&#xff0c;觉得是 bug&#xff0c;再试的时候又正常了。 碰到这样的事情&#xff0c;职业素养和测试人员长期养成的死磕的习性会让她…

SpringBoot工程引用其他工程构建的jar包

1、问题 存在A、B两个工程&#xff0c;其中B工程需要引用A工程的jar包。 2、解决办法 A工程 &#xff08;1&#xff09;自动配置bean。 Configuration ComponentScan("cn.ac.trimps.auth.**") public class AuthClientConfig {} Retention(RetentionPolicy.RUNTIME…