JAVA高阶私房菜:JVM虚拟机核心概念及参数微调实验

news2024/12/25 22:08:20

目录

基础快速掌握

什么是JVM虚拟机

JVM的的实现

操作系统-虚拟机-JRE-JDK的关系

生产环境部署JDK还是JRE

JVM内存组成部分和堆空间分布

内存组成

堆空间内存分布

内存分布

堆空间分配

JVM堆空间垃圾回收流程及JVM参数

 垃圾回收流程

JVM参数分类

JVM参数格式分类

JVM堆栈内存配置参数

JVM常见的命令行参数配置

JVM虚拟机栈参数调整和溢出案例

JVM虚拟机栈参数调整

调试代码查看栈帧

栈溢出抛错测试

Jmeter5.x压测案例

  压测参数

 JVM参数

JDK8之后的方法区实现和元空间的联系

什么是方法区和元空间

元空间大小配置

什么时候容易出现元空间不足


         JVM迄今为止都是程序员老生常谈的话题,实话说我每一次研究探索完后都会忘一次,但好在每次都有新的见解,再加上JDK每迭代更新一版都会有新的特性和改良,对此,我们就当温故知新,增进新的理解,弥补不足,在这里我们不讲大而全的知识,也不会讲老旧的知识点,主要围绕在工作和面试中最高频的点,聚焦于JDK9之后的关键内容进行剖析。

基础快速掌握

什么是JVM虚拟机

        Java Virtual Machine是一种虚拟机,它是Java程序运行的环境。JVM提供了Java程序的运行时环境,包括内存管理、垃圾回收、安全性、类加载等功能,是Java语言的核心,它使Java语言具有跨平台的特性(一次编译四处运行)。

JVM的的实现

虚拟机名称说明
HotSpot是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机,主要使用C++实现,JNI接口部分用C实现
JRockit除 HotSpot 之外另一款比较厉害的 VM, 一开始是BEA 公司的,一度获取运行最快的虚拟机。 Oracle 在 2008 年收购了 BEA 公司,JRockit 与 HotSpot 同属于 Oracle
J9 VM基于IBM公司开发的JDK,主要应用在IBM公司开发的的软件或服务器端,如:嵌入式、服务端、桌面等,基本上IBM本司出品的产品都是用的J9 VM

        JVM有以上产品实现,这里主要列了这几个,当然还有其他的实现,这些JVM在具体实现上会存在一些差异,而且在不同的场景下他们表现都不一样,这些差异主要体现在性能、稳定性、兼容性等多个方面,虽说有诸多区别,但所提供的基础能力都基本一致

操作系统-虚拟机-JRE-JDK的关系

        操作系统:操作系统是计算机硬件和应用程序之间的桥梁,负责管理计算机的硬件资源,如CPU、内存、硬盘和网络等。

        虚拟机:虚拟机是一种软件,它在操作系统之上运行,提供了一个独立的、虚拟的计算机环境,用于执行Java程序。

        JRE:Java Runtime Environment(JRE)是Java程序的运行环境,它包含Java虚拟机(JVM)和Java类库。它提供了Java程序运行所需的基本环境,但它没有提供Java程序的开发工具

        JDK:Java Development Kit(JDK)是Java程序的开发工具包,它包含JRE、编译器、调试器和其他开发工具,提供了Java程序的开发、编译、调试和部署所需的全部工具。

生产环境部署JDK还是JRE

  • 在生产环境部署Java程序时,一般会选择安装JRE而不是JDK

  • JRE安装包更小,打包成镜像更省空间,但是缺少相关调试开发工具,比如以下的

    • 编译器:JRE中没有Java编译器,无法将Java源代码编译成字节码文件。

    • 调试器:JRE中没有Java调试器,无法进行Java程序的调试和测试

  • 但在某些特殊情况下,如需要进行Java程序的开发、编译、调试等操作时,就需要安装JDK

JVM内存组成部分和堆空间分布

内存组成

        基于JDK8的HotSpot虚拟机,不同虚拟机不同版本会有不一样

名称作用特点
程序计数器也叫PC寄存器,用于记录当前线程执行的字节码指令位置,以便线程在恢复执行时能够从正确的位置开始线程私有
Java虚拟机栈用于存储Java方法执行过程中的局部变量、方法参数和返回值,以及方法执行时的操作数栈线程私有
本地方法栈用于存储Java程序调用本地方法的参数和返回值等信息。线程私有
用于存储Java程序创建的对象,所有线程共享一个堆,堆中的对象可以被垃圾回收器回收,以便为新的对象分配空间线程共享
元数据区用于存储类的元数据信息,如类名、方法名、字段名等,以及动态生成的代理类、动态生成的字节码等 元空间是位于本地(直接)内存中的,而不是像JDK8之前方法区位于堆内存中的。线程共享

堆空间内存分布

内存分布

        用于存储Java程序创建的对象,所有线程共享一个堆,堆中的对象可以被垃圾回收器回收,以便为新的对象分配空间。

堆空间分配

JVM堆空间垃圾回收流程及JVM参数

 垃圾回收流程

  • 新建对象,放到Eden区,满后触发Minor GC(每次都是由Eden区满触发Minor GC,接连放对象到S0或S1

  • 存活的对象移动到Survivor的S0区,如果S0满后触发Minor GC

  • S0存活下来的对象移动到S1区,然后S0区空闲

  • S1满后触发Minor GC,再次移动到S0区,然后S1区空闲

  • 反复GC每次对象涨1岁,到达一定次数后(默认15),进入老年代

  • 当老年代内存不足会触发Full GC,出现STW(Stop-The-World)

  • 堆被垃圾回收,基本都是采用分代收集算法,不通区域的采用不同的垃圾回收算法

  • 方法结束后,堆中的对象不会马上移除,在垃圾回收的时候才会被移除(不是实时GC的,ThreadLocal里面说过)

直通车:Java高阶私房菜:深入解析多线程场景下ThreadLocal应用-CSDN博客

JVM参数分类

JVM参数格式分类
格式解释例子
标准参数(-)所有JVM都实现这些参数的功能-verbose:gc 打印GC简要信息
非标准参数(-X)不保证所有JVM实现都满足-Xmx2048m等价 -XX:MaxHeapSize JVM最大堆内存为2048M
非稳定参数(-XX)不稳定未来可能取消,但很有用-XX:+PrintGCDetails每次GC时打印详细信息。
-XX:+开启对应的参数-XX:+PrintGCDetails 开启每次GC时打印详细信息。
-XX:-关闭对应的参数-XX:-DisableExplicitGC 禁止调用System.gc()
-XX:=设定数字参数-XX:NewRatio=2 新生代和老年代内存比例
JVM堆栈内存配置参数
参数解释
-Xms初始堆大小,推荐和最大堆一样
-Xmx最大堆大小,推荐和初始堆一样
-Xmn年轻代大小
-Xss每个线程的栈大小
JVM常见的命令行参数配置
参数解释
-XX:+PrintGCDetails打印GC回收信息
-XX:NewRatio新生代和老年代空间大小的比率,由-XX:NewRatio参数控制 -XX:NewRatio参数的默认值是2,表示新生代和老年代的比例是1:2 如果将-XX:NewRatio设置为4,表示新生代和老年代的比例是1:4
-XX:MaxMetaspaceSize元空间所分配内存的最大值,默认没限制
-XX:+UseConcMarkSweepGC设置并发收集器

JVM虚拟机栈参数调整和溢出案例

JVM虚拟机栈参数调整

        栈是用来存储Java程序中的方法调用和局部变量的内存区域,每个线程都有自己的虚拟机栈,其生命周期与线程相同。当一个方法被调用时,Java虚拟机会在该线程的虚拟机栈中创建一个栈帧,用来存储该方法的局部变量、方法返回值等信息。

        默认情况下,JVM虚拟机栈的大小是固定的,JDK1.5后通常为1MB。如果线程在执行方法时需要更多的栈空间,JVM会抛出StackOverflowError异常,JVM参数 xss,比如 -Xss1m 表示1MB。

调试代码查看栈帧

public class StackFrameDemo {

    public static void main(String[] args) {
        StackFrameDemo demo = new StackFrameDemo();
        demo.method1();
    }

    public void method1() {
        String str = "Hello";
        method2(str);
        System.out.println("method1--完成");
    }

    public void method2(String str) {
        int num = 123;
        method3(str, num);
        System.out.println("method2--完成");
    }

    public void method3(String str, int num) {
        double d = 3.14;
        method4(str, num, d);
        System.out.println("method3--完成");
    }

    public void method4(String str, int num, double d) {
        // 查看当前栈帧信息
        System.out.println("Current Stack Frame:");
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement element : stackTrace) {
            System.out.println(element.toString());
        }
        System.out.println("method4--完成");

    }
}

栈溢出抛错测试

  • 栈越小,递归调用的次数就越少,因为栈空间不足导致栈溢出异常

  • 栈越大,递归调用的次数就越多,因为有足够的栈空间来存储方法调用的信息

//栈参数,最少208k
-Xss524k
-Xss1m
-Xss10m

//代码案例
public class StackSizeDemo {

    private static int count = 0;

    public static void main(String[] args) {
        try {
            recursiveMethod();
        } catch (Throwable t) {
            System.out.println("Stack overflow after " + count + " invocations.");
            t.printStackTrace();
        }
    }

    private static void recursiveMethod() {
        count++;
        recursiveMethod();
    }
}

Jmeter5.x压测案例

@RestController
@RequestMapping("api/v1/data")
public class DataController {

    @RequestMapping("compute")
    public String compute() {
        Byte[] b = new Byte[1024*1024];
        return "success";
    }
}

  压测参数

 JVM参数

        参数-Xms64m -Xmx64m

         参数 -Xms640m -Xmx640m ​​​​​

JDK8之后的方法区实现和元空间的联系

什么是方法区和元空间

        方法区是JVM中用来存储类的元数据信息的区域,包括类的结构、方法、字段信息等,Java堆类似各个线程共享的内存区域

        元空间、永久代是方法区具体的落地实现Java8之前是称之为永久代(PermGen),java8后引入了一个新概念元空间用于替代旧版JVM中的永久代。

  • 方法区和永久代以及元空间的关系很像 Java 中接口和类的关系

  • 类实现了接口,类就可以看作是永久代和元空间,接口可以看作是方法区

  • 永久代是 JDK 1.8 之前的方法区实现,JDK 1.8 及以后方法区的实现便成为元空间

        元空间的大小是动态的,可以根据需要进行自动扩展,如果元空间不足,JVM会抛出 OutOfMemoryError : Metaspace

元空间大小配置

-XX:MetaspaceSize

        用来设置元空间初始大小的参数,它的默认值是21 MB

-XX:MaxMetaspaceSize

        用来设置元空间最大大小的参数,它的默认值是-1 即不限制,使用的是本地内存,不像旧版的永久代是堆内存。如果不限制元空间的大小,可能会导致元空间占用过多的内存,从而引起内存溢出。

系统参数查看

        这两个参数的单位是字节(B),可以使用K、M、G等后缀来表示更大的单位。

public class HeapDemo {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("元空间溢出测试");
        Thread.sleep(10000000);
    }
}
jps #查看进程号
jinfo -flag MetaspaceSize 进程号  #查看Metaspace分配内存空间 
jinfo -flag MaxMetaspaceSize 进程号 #查看Metaspace最大空间
# 调整参数
-XX:MetaspaceSize=126m -XX:MaxMetaspaceSize=524m

当空间不足时抛出异常信息: “Java.Lang.OutOfMemoryError:Metaspace”

什么时候容易出现元空间不足

  • 应用程序使用大量的反射技术,例如使用Class.forName()等方法加载类,或者使用Java Reflection API进行操作

  • 使用大量的动态代理技术,例如使用Java Proxy类等技术

  • 使用大量的注解,例如使用Spring框架的注解等

  • 使用的第三方库过多,这些库可能会在运行时动态生成新的类,导致元空间内存占用过多。

  • 应用程序的业务逻辑比较复杂,需要加载大量的类

  • 应用程序使用大量的JSP页面,其中每个页面都对应一个类文件(现在很少)

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

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

相关文章

山东大学操作系统实验一(Linux虚拟机实现)

目录 实验题目 实验要求 示例程序 主程序 头文件 重点代码解析 一、main函数的参数 参数介绍 参数输入方式 本块代码 二、信号处理 本块代码 原理介绍 实现效果 三、kill函数 功能介绍 使用方式 本块代码 四、头文件处理 本块代码 代码作用 实验程序 …

Python数据可视化:频率统计条形图countplot()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 Python数据可视化: 频率统计条形图 countplot() [太阳]选择题 请问关于以下代码表述正确的选项是? import seaborn as sns import matplotlib.pyplot as plt data { …

二、python+前端 实现MinIO分片上传

python前端 实现MinIO分片上传 一、背景二、流程图三、代码 一、背景 问题一:前端 -> 后端 ->对象存储 的上传流程,耗费带宽。 解决方案:上传流程需要转化为 前端 -> 对象存储,节省上传带宽 问题二:如果使用…

Leetcode 第394场周赛 问题和解法

题目 统计特殊字母的数量 I 给你一个字符串word。如果word中同时存在某个字母的小写形式和大写形式,则称这个字母为特殊字母。 返回word中特殊字母的数量。 示例 1: 输入:word "aaAbcBC"输出:3解释:word 中的特殊…

【Entity Framework】聊一聊EF如何使用数据库函数

【Entity Framework】聊一聊EF如何使用数据库函数 文章目录 【Entity Framework】聊一聊EF如何使用数据库函数一、数据库函数的类型二、内置函数与用户定义的函数四、聚合函数、标量函数和表值函数五、Niladic函数六、EF Core 中的数据库函数映射6.1 内置函数映射6.2 EF.Functi…

【iOS开发】(四)react Native第三方组件五个20240419-20

react native 外的 第三方组件 目录标题 react native 外的 第三方组件(一)与rn核心组件的使用步骤区别:(二)第三方组件概览1 WebView2 Picker3 Swiper4 AsyncStorage5 Geolocation6 Camera (三)详细学习1 WebViewCoco…

ROS1快速入门学习笔记 - 01Linux基础

目录 一、Linux极简基础 二、C与Python极简基础 1. for循环 2. while循环 3. 面向对象 一、Linux极简基础 终端快捷键:ctrlaltt 命令行的操作方式 查看当前终端所在路径:pwd切换路径cd;例如cd /home/ 进入home文件夹;cd …

Oracle Hint 语法详解

什么是Hint Hint 是 Oracle 提供的一种 SQL 语法,它允许用户在 SQL 语句中插入相关的语法,从而影响 SQL 的执行方式。 因为 Hint 的特殊作用,所以对于开发人员不应该在代码中使用它,Hint 更像是 Oracle 提供给 DBA 用来分析诊断问…

2024数学建模时间汇总与竞赛攻略

目录 2024数学建模汇总(时间、报名费、获奖率、竞赛级别、是否可跨校) 中国高校大数据挑战赛 “华数杯”国际大学生数学建模竞赛 美国大学生数学建模竞赛(美赛) 数学中国(认证杯)数学建模网络挑战赛 …

从国九条的颁布简单看待未来的因子轮动

上周4月12日《关于加强监管防范风险推动资本市场高质量发展的若干意见》又称国九条出台后,除了本周五中东局势对大盘的影响,本周一波三折的行情很大程度上都是围绕着国九条展开的。一个很有意思的现象是前两次国九条发布后,市场都诞生了波澜壮…

【Linux开发 第八篇】定时任务

定时任务 crond任务调度at定时任务 crond任务调度 任务调度: 是指系统在某个时间执行特定的命令或程序 任务调度分类: 系统工作:有些重要的工作必须周而复始地执行,如病毒扫描等 个别用户工作:个别用户可能希望执行某…

107页 | 企业数字化转型规划设计(免费下载)

【1】关注本公众号,转发当前文章到微信朋友圈 【2】私信发送 【企业数字化转型规划设计】 【3】获取本方案PDF下载链接,直接下载即可。 如需下载本方案PPT原格式,请加入微信扫描以下方案驿站知识星球,获取上万份PPT解决方案&…

JAVA-服务器搭建-创建web后端项目

首先打开IDEA 点击新建项目 写好名称-模板选择 Web应用程序 -语言选择 Java 构建系统选择 Maven 然后点击下一步 选择版本-选择依赖项 Web Profile 点击创建 点击当前文件-选择编辑配置 选择左上角的加号-选择Tomcat服务器-选择本地 点击配置-选择到Tomcat目录-点击确定 起个…

Postman之安装

Postman工具之介绍与安装 Postman是什么?Postman有几种安装方式? Postman是什么? postman是一款http客户端的模拟器,它可以模拟发出各种各样的网络请求,用于接口测试。 Postman有几种安装方式? 两种&…

【数学建模】优劣解距离法Topsis模型(含MATLAB代码)

TOPSIS法,全称 Technique for Order Preference by Similarity to an Ideal Solution,是由C.L.Hwang和K.Yoon于1981年首次提出的 。这是一种多目标决策分析中常用的有效方法,也被称作优劣解距离法 。 TOPSIS法的基本原理是通过检测评价对象与…

Abaqus python二次开发2-扭转弹簧刚度计算

Abaqus python二次开发2-扭转弹簧刚度计算 1、定义弹簧参数2、绘制弹簧2.1、绘制弹簧截面2.12、绘制弹簧实体part(螺旋旋转截面) 3、设置材料、截面属性、并赋给弹簧(set)4、创建组件的坐标系、参考点和instance(弹簧&…

政安晨:【Keras机器学习示例演绎】(五)—— 利用视觉变换器进行物体检测

目录 导言 导入和设置 准备数据集 实施多层感知器(MLP) 实施补丁创建层 显示输入图像的补丁 实施补丁编码层 构建 ViT 模型 运行实验 评估模型 政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 收录专栏: TensorFlow与…

4.9 启动系统任务❤❤❤

有一些特殊的任务需要在系统启动时执行,例如配置文件加载、数据库初始化等操作。 Spring Boot对此提供了两种解决方案:CommandLineRunner和ApplicationRunner。 CommandLineRunner和ApplicationRunner基本一致,差别主要体现在参数上。 1. Co…

【Linux】在centos快速搭建K8S1.18集群

使用 kubeadm 创建集群帮助文档 如果您需要以下几点,该工具是很好的选择:kubeadm 一种简单的方法,让你尝试 Kubernetes,可能是第一次。现有用户自动设置群集并测试其应用程序的一种方式。其他生态系统和/或安装程序工具中的构建…

sublime text的json快捷键

系统 macos 配置 sublime Text->Settings->Key Bindings 效果 可以看到,按:shiftcommandp,会出现快捷键窗口,打pretty,会出现Format JSON,最右侧显示⌘J,说明只需要macos的⌘和J同时按…