本文分享自华为云社区《【性能优化】JVM整体架构与调优参数说明》,作者: 冰 河。

JVM的分类

这里,我们先来说说什么是VM吧,VM的中文含义为:虚拟机,指的是使用软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统,是物理机的软件实现。

常用的虚拟机有:VMWare、Virtual Box,Java Virtual Machine(JVM,Java虚拟机)。

这里,我们重点聊的就是JVM,Java虚拟机。看下图。

这张图看起来还是比较简单的,JVM运行于操作系统之上,操作系统是运行在计算机硬件上的。

关于JVM,其实有很多大厂开发了不同版本的JVM,比较知名的有:Sun HotSpot VM、BEA JRockit VM、IBM J9 VM、 Azul VM、 Apache Harmony、 Google Dalvik VM、 Microsoft JVM等等。

现在使用的比较多的JDK8版本就是Sun HotSpot VM与BEA JRockit VM合并之后开发出的JDK版本。

JVM的构成

JVM主要由三个子系统构成,分别为:类加载器子系统、运行时数据区(内存结构)和字节码执行引擎。

为了更好的理解JVM,我们来看一下JVM的全貌图。

当我们开发Java程序时,首先会编写.java文件,之后,会将.java文件编译成.class文件。

JVM中,会通过类装载子系统将.class文件的内容装载到JVM的运行时数据区,而JVM的运行时数据区又会分为:方法区、堆、栈、本地方法栈和程序计数器 几个部分。

在装载class文件的内容时,会将class文件的内容拆分为几个部分,分别装载到JVM运行时数据区的几个部分。其中,值得注意的是:程序计数器的作用是:记录程序执行的下一条指令的地址。

方法区也叫作元空间,主要包含了:运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应的Class实例的引用等信息。

在JVM中,程序的执行是通过执行引擎进行的,执行引擎会调用本地方法的接口来执行本地方法库,进而完成整个程序逻辑的执行。

我们常说的垃圾收集器是包含在执行引擎中的,在程序的运行过程中,执行引擎会开启垃圾收集器,并在后台运行,垃圾收集器会不断监控程序运行过程中产生的内存垃圾信息,并根据相应的策略对垃圾信息进行清理。

这里,大家需要注意的是:栈、本地方法栈和程序计数器是每个线程运行时独占的,而方法区和堆是所有线程共享的。所以,栈、本地方法栈和程序计数器不会涉及线程安全问题,而方法区和堆会涉及线程安全问题。

方法区(元空间)

很多小伙伴一看到方法区三个字,脑海中的第一印象可能是存储方法的地方吧。

实则不然,方法区的另一个名字叫作元空间,相信不少小伙伴或多或少的听说过元空间。这个区域是JDK1.8中划分出来的。主要包含:运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应的Class实例的引用等信息。方法区中的信息能够被多个线程共享。

例如,在程序中声明的常量、静态变量和有关于类的信息等的引用,都会存放在方法区,而这些引用所指向的具体对象 一般都会在堆中开辟单独的空间进行存储,也可能会在直接内存中进行存储。

堆中主要存储的是实际创建的对象,也就是会存储通过new关键字创建的对象,堆中的对象能够被多个线程共享。堆中的数据不需要事先明确生存期,可以动态的分配内存,不再使用的数据和对象由JVM中的GC机制自动回收。对JVM的性能调优一般就是对堆内存的调优。

Java中基本类型的包装类:Byte、Short、Integer、Long、Float、Double、Boolean、Character类型的数据是存储在堆中的。

堆一般会被分成年轻代和老年代。而年轻代又会被进一步分为1个Eden区和2个Survivor区。在内存分配上,如果保持默认配置的话,年轻代和老年代的内存大小比例为1 : 2,年轻代中的1个Eden区和2个Survivor区的内存大小比例为:8 : 1 : 1。

栈一般又叫作线程栈或虚拟机栈,一般存储的是局部变量。在Java中,每个线程都会有一个单独的栈区,每个栈中的元素都是私有的,不会被其他的栈所访问。栈中的数据大小和生存期都是确定的,存取速度比较快。

在Java中,所有的基本数据类型(byte、short、int、long、float、double、boolean、char)和引用变量(对象引用)都是在栈中的。一般情况下,线程退出或者方法退出时,栈中的数据会被自动清除。

程序在执行过程中,会在栈中为不同的方法创建不同的栈帧,在栈帧中又包含了:局部变量表、操作数栈、动态链接和方法出口。

关于局部变量表、操作数栈、动态链接和方法出口的具体作用,会在《架构师进阶系列》中的后续文章中详细阐述。

栈中一般会存储对象的引用,这些引用所指向的具体对象一般都会在堆中开辟单独的地址空间进行存储,也有可能存储在直接内存中。

注意: 这里说的是这些引用所指向的具体对象一般都会在堆中开辟单独的地址空间进行存储,也有可能存储在直接内存中。

因为在JVM中,如果开启了逃逸分析和标量替换,则可能不会再在堆上创建对象,可能会将对象直接分配到栈上,也可能不再创建对象,而是进一步分解对象中的成员变量,将其直接在栈上分配空间并赋值。

本地方法栈

本地方法栈相对来说比较简单,就是保存native方法进入区域的地址。

例如,在Java中创建线程,调用Thread对象的start()方法时,会通过本地方法start0()调用操作系统创建线程的方法。此时,本地方法栈就会保存start0()方法进入区域的内存地址。

程序计数器

程序计数器也叫作PC计数器,只要存储的是下一条将要执行的命令的地址。

JVM调优参数

在JVM中,主要是对堆(新生代)、方法区和栈进行性能调优。各个区域的调优参数如下所示。

  • 堆:-Xms、-Xmx
  • 新生代:-Xmn
  • 方法区(元空间):-XX:MetaspaceSize、-XX:MaxMetaspaceSize
  • 栈(线程):-Xss

为了更加直观的表述,我们可以将JVM的内存区域和对应的调优参数总结成下图所示。

在设置JVM启动参数时,需要特别注意方法区(元空间)的参数设置。

关于方法区(元空间)的JVM参数主要有两个:-XX:MetaspaceSize和-XX:MaxMetaspaceSize。

-XX:MetaspaceSize: 指的是方法区(元空间)触发Full GC的初始内存大小(方法区没有固定的初始内存大小),以字节为单位,默认为21M。达到设置的值时,会触发Full GC,同时垃圾收集器会对这个值进行修改。

如果在发生Full GC时,回收了大量内存空间,则垃圾收集器会适当降低此值的大小;如果在发生Full GC时,释放的空间比较少,则在不超过设置的-XX:MetaspaceSize值或者在没设置-XX:MetaspaceSize的值时不超过21M,适当提高此值。

-XX:MaxMetaspaceSize: 指的是方法区(元空间)的最大值,默认值为-1,不受堆内存大小限制,此时,只会受限于本地内存大小。

最后需要注意的是: 调整方法区(元空间)的大小会发生Full GC,这种操作的代价是非常昂贵的。如果发现应用在启动的时候发生了Full GC,则很有可能是方法区(元空间)的大小被动态调整了。

所以,为了尽量不让JVM动态调整方法区(元空间)的大小造成频繁的Full GC,一般将-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置成一样的值。例如,物理内存8G,可以将这两个值设置为256M

最后,我们一起看下在物理内存8G的情况下,启动应用程序时,可以设置的JVM参数。当然,我这里给出的是一些经验值,实际部署到生产环境时,需要经过压测找到最佳的参数值。

  • 启动SpringBoot
java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar xxx.jar
  • 启动Tomcat(Linux)

在Tomcat bin目录下catalina.sh文件里配置。

‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M
  • 启动Tomcat(Windows)

在Tomcat bin目录下catalina.bat文件里配置。

‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M

总结

今天,我们一起学习了JVM的整体架构和调优参数,主要包括:JVM的总体结构、JVM的分类、JVM的构成和调优参数。你学会了吗?欢迎在文末留言说出你的想法,如果你有更好的见解,也可以在文末留言和大家交流。

点击关注,第一时间了解华为云新鲜技术~

浅谈JVM整体架构与调优参数的更多相关文章

  1. MGR架构~ 整体性能架构的调优

    一 简介:MGR集群架构的调优二 过程:本文将从各个角度来具体阐述下三 硬件    1 硬件选择相同配置的服务器,磁盘,内存,cpu性能越高越好四 网络    1 0丢包和最好万兆网卡五 MGR本身  ...

  2. 【架构】浅谈web网站架构演变过程

    浅谈web网站架构演变过程   前言 我们以javaweb为例,来搭建一个简单的电商系统,看看这个系统可以如何一步步演变.   该系统具备的功能:   用户模块:用户注册和管理 商品模块:商品展示和管 ...

  3. 朱晔的互联网架构实践心得S2E6:浅谈高并发架构设计的16招

    朱晔的互联网架构实践心得S2E6:浅谈高并发架构设计的16招 概览 标题中的高并发架构设计是指设计一套比较合适的架构来应对请求.并发量很大的系统,使系统的稳定性.响应时间符合预期并且能在极端的情况下自 ...

  4. JVM底层原理及调优之笔记一

    JVM底层原理及调优 1.java虚拟机内存模型(JVM内存模型) 1.堆(-Xms -Xmx -Xmn) java堆,也称为GC堆,是JVM中所管理的内存中最大的一块内存区域,是线程共享的,在JVM ...

  5. JVM原理讲解和调优

    一.什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现 ...

  6. [原创] 浅谈ETL系统架构如何测试?

    [原创] 浅谈ETL系统架构如何测试? 来新公司已入职3个月时间,由于公司所处于互联网基金行业,基金天然固有特点,基金业务复杂,基金数据信息众多,基金经理众多等,所以大家可想一下,基民要想赚钱真不容易 ...

  7. 浅谈jvm中的垃圾回收策略

    下面小编就为大家带来一篇浅谈jvm中的垃圾回收策略.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧   java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已 ...

  8. JVM基本配置与调优

    JVM基本配置与调优 JVM调优,一般都是针对堆内存配置调优. 如图:堆内存分新生代和老年代,新生代又划分为eden区.from区.to区. 一.区域释义 JVM内存模型,堆内存代划分为新生代和老年代 ...

  9. 浅谈C++三层架构

    浅谈C++三层架构 三层架构并不是MVC,MVC是一个很早就有的经典的程序设计模式,M-V-C分为三层,M(Model)-V(View)-C(Control). web开发中的三层架构是指:数据访问层 ...

  10. JVM性能调优的6大步骤,及关键调优参数详解

    JVM性能调优方法和步骤1.监控GC的状态2.生成堆的dump文件3.分析dump文件4.分析结果,判断是否需要优化5.调整GC类型和内存分配6.不断分析和调整JVM调优参数参考 对JVM内存的系统级 ...

随机推荐

  1. [BUUCTF][WEB][极客大挑战 2019]Upload 1

    打开靶机url,看到一个页面可以上传文件 上传一个图片试一下,发现上传的路径是 http://a7661b03-4852-41de-9ea4-d48c47cb50f0.node4.buuoj.cn:8 ...

  2. pikachu SQL-inject insert/update注入

    insert 注入 (修改信息处是update注入,和此处同理) 注册页面,用户处输入 1' 发现报错信息 You have an error in your SQL syntax; check th ...

  3. 阿里云 SMS 短信 Java SDK 封装

    Github & Issues: https://github.com/cn-src/aliyun-sms 官方文档:https://help.aliyun.com/document_deta ...

  4. 【算法day6】哈希表、有序表、链表(反转单链表)

    哈希表的简单介绍 1)哈希表在使用层面上可以理解为一种集合结构 2)如果只有key,没有伴随数据value,可以使用HashSet结构(C++中叫UnOrderedSet) 3)如果既有key,又有伴 ...

  5. 矩池云上 git clone --recursive 出错,怎么解决

    遇到问题 有时候安装包教程里 git clone 的时候会出现以下错误: git clone --recursive https://github.91chi.fun/https://github.c ...

  6. 带你领略下iOS中OC的“alloc”源代码,让你在工作中不在迷惑

    前言 前面我们使用官方开源的objc源码进行了编译调试 objc4-818.2源码编译调试笔记 前言为什么会想要调试源码? 苹果开源了部分源码, 但相似内容太多, 基本找不到代码见的对应关系, 如果能 ...

  7. [Rust] 命名习惯

    [Rust] 命名习惯 通用习惯 CamelCase: 首位是大写字母的单词,没有分隔符: snake_case: 使用下划线作为分隔符,小写单词: SCREAMING_SNAKE_CASE: 使用下 ...

  8. Oracle触发器联合唯一约束

    Oracle支持可为空字端的唯一约束呢?下面就是用触发器作出的限制语句,仅供参考: CREATE OR REPLACE TRIGGER Tg_Completion_Test BEFORE INSERT ...

  9. DataGear数据可视化分析平台介绍

    DataGear 是一款开源免费的数据可视化分析平台,自由制作任何您想要的数据看板,支持接入SQL.CSV.Excel.HTTP接口.JSON等多种数据源. 系统特点: 友好的数据源接入 支持运行时接 ...

  10. 基于 Nebula Graph 构建百亿关系知识图谱实践

    本文首发于 Nebula Graph Community 公众号 一.项目背景 微澜是一款用于查询技术.行业.企业.科研机构.学科及其关系的知识图谱应用,其中包含着百亿级的关系和数十亿级的实体,为了使 ...