【JVM详解JVM优化】聊聊JVM优化

简介:

前面两期文章讲了JVM内存模型:【JVM详解&JVM优化】JVM内存模型-CSDN博客

以及JVM垃圾回收机制:【JVM详解&JVM优化】JVM垃圾回收机制-CSDN博客

        在本篇文章中,我们将深入探讨Java虚拟机(JVM)的优化策略,以提升Java应用的性能和效率。JVM是Java程序运行的核心,其内部机制和参数设置直接影响应用的表现。文章将首先概述JVM的基本结构和内存管理,帮助读者理解优化的必要性。

        接下来,我们将探讨多种JVM优化技术,包括堆内存的合理配置、垃圾收集器的选择与调优,以及如何通过JVM参数调整(如-Xms-Xmx-XX:+UseG1GC等)来提高性能。此外,文章还将涵盖常见的性能监测工具和技术,如Java VisualVM和JProfiler,帮助开发者实时分析和诊断应用性能瓶颈。

        最后,本文将分享一些实际调优经验,展示如何在真实环境中应用这些优化策略,以确保Java应用的高效性和稳定性。无论你是初学者还是经验丰富的开发者,本篇文章都将为你提供实用的见解和建议,助你在JVM优化的道路上更进一步。


一、常见的优化策略

1. 调整 JVM 参数

  • 堆大小: 根据应用需求设置合适的堆内存大小(-Xms-Xmx)。

    -Xms512m -Xmx2048m
  • 年轻代与老年代比例: 调整年轻代和老年代的比例,可以使用 -XX:NewRatio 参数。例如,设置年轻代为老年代的 1:2:

    -XX:NewRatio=2
  • GC 策略: 选择适合应用场景的垃圾回收策略,如 G1、CMS 或 ZGC:

    -XX:+UseG1GC

 常用JVM参数参考

  • jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)

  • jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)

  • jdk1.9 默认垃圾收集器G1

-XX:+PrintCommandLineFlags jvm参数可查看默认设置收集器类型

-XX:+PrintGCDetails亦可通过打印的GC日志的新生代、老年代名称判断

2. 监控和分析

  • JVM 监控工具: 使用 JVisualVM、JConsole 等工具监控内存使用情况、CPU 性能和线程活动。
  • Heap Dump 分析: 分析堆转储文件,查找内存泄漏和对象创建情况。
  • 通过观察 GC 频率和停顿时间,来进行 JVM 内存空间调整,使其达到最合理的状态。调整过程记得小步快跑,避免内存剧烈波动影响线上服务。 

3. 优化代码

  • 减少对象创建: 尽量复用对象,使用对象池等技术,降低 GC 压力。
  • 使用基本数据类型: 尽量使用基本数据类型而非包装类型,减少内存消耗。
  • 优化循环和递归: 避免不必要的循环和递归调用,优化算法复杂度。

4. JIT 编译优化

  • 方法内联: 让 JIT 编译器内联小方法,以减少方法调用的开销。
  • 编译级别: 调整 JIT 编译器的编译级别,可以使用 -XX:CompileThreshold 来设置编译阈值。

5. 配置类加载

  • 类加载器: 自定义类加载器,优化类的加载和卸载过程。
  • 避免重复加载: 确保类不被重复加载,避免因类加载导致的内存浪费。

6. 线程优化

  • 线程池: 使用线程池管理线程,避免频繁创建和销毁线程。
  • 锁优化: 尽量减少锁的粒度,使用读写锁等减少线程竞争。

7. 垃圾回收调优

  • 调节 GC 频率: 使用 -XX:MaxGCPauseMillis 和 -XX:GCTimeRatio 等参数调节 GC 行为。
  • 避免 Full GC: 优化堆的使用,避免频繁的 Full GC,确保大对象存放在老年代。

8. 使用现代 JVM 特性

  • 逃逸分析: 利用逃逸分析优化对象的分配,减少不必要的堆分配。
  • JVM 热点特性: 利用 JVM 热点特性,进行持续的性能调优。

逃逸分析(Escape Analysis)是目前Java虚拟机中比较前沿的优化技术。

这是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。(不要在轻易回答面试官,所有对象都是在堆上创建了)

逃逸分析的基本原理是:

分析对象动态作用域,当一个对象在方法里面被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,这种称为方法逃逸;

甚至还有可能被外部线程访问到,譬如赋值给可以在其他线程中访问的实例变量,这种称为线程逃逸;

从不逃逸、方法逃逸到线程逃逸,称为对象由低到高的不同逃逸程度。

JVM中通过如下参数可以指定是否开启逃逸分析:

-XX:+DoEscapeAnalysis :表示开启逃逸分析。

-XX:-DoEscapeAnalysis :表示关闭逃逸分析。

开启逃逸分析,编译器可以对代码进行如下优化:

1、同步消除:如果一个对象被逃逸分析发现只能被一个线程所访问,那对于这个对象的操作可以不同步。

2、栈上分配:如果确定一个对象不会逃逸出线程之外,那让这个对象在栈上分配内存将会是一个很不错的主意,对象所占用的内存空间就可以随栈帧出栈而销毁。

3、标量替换:如果一个对象被逃逸分析发现不会被外部方法访问,并且这个对象可以拆散,那么程序真正执行的时候将可能不去创建这个对象,而改为直接创建它的若干个比这个方法使用的成员变量来代替。将对象拆分后,可以让对象的成员变量在栈上分配和读写。

通过综合运用这些策略,可以显著提高 JVM 的性能和响应速度,确保 Java 应用程序在生产环境中的高效运行。根据具体应用场景,选择合适的优化策略进行调整。


二、调优经验

        JVM的性能优化可以分为代码层面和非代码层面。

        在代码层面,大家可以结合字节码指令进行优化,比如一个循环语句,可以将循环不相关的代码提取到循环体之外,这样在字节码层面就不需要重复执行这些代码了。

        在非代码层面,一般情况可以从内存、gc以及cpu占用率等方面进行优化。

        注意,JVM调优是一个漫长和复杂的过程,而在很多情况下,JVM是不需要优化的,因为JVM本身已经做了很多的内部优化操作。


        Java整个堆大小设置,Xmx 和 Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍,Xmx和Xms的大小设置为一样,避免GC后对内存的重新分配。而Full GC之后的老年代内存大小,我们可以通过前面在Visual VM中添加的插件Visual GC查看。先手动进行一次GC,然后查看老年代的内存占用。

        新生代Xmn的设置为老年代存活对象的1-1.5倍。

        老年代的内存大小设置为老年代存活对象的2-3倍。


        JVM配置方面,一般情况可以先用默认配置(基本的一些初始参数可以保证一般的应用跑的比较稳定了),在测试中根据系统运行状况(会话并发情况、会话时间等),结合gc日志、内存监控、使用的垃圾收集器等进行合理的调整,当老年代内存过小时可能引起频繁Full GC,当内存过大时Full GC时间会特别长。

        那么JVM的配置比如新生代、老年代应该配置多大最合适呢?答案是不一定,调优就是找答案的过程,物理内存一定的情况下,新生代设置越大,老年代就越小,Full GC频率就越高,但Full GC时间越短;相反新生代设置越小,老年代就越大,Full GC频率就越低,但每次Full GC消耗的时间越大。建议如下:

        -Xms和-Xmx的值设置成相等,堆大小默认为-Xms指定的大小,默认空闲堆内存小于40%时,JVM会扩大堆到-Xmx指定的大小;空闲堆内存大于70%时,JVM会减小堆到-Xms指定的大小。如果在Full GC后满足不了内存需求会动态调整,这个阶段比较耗费资源。

        新生代尽量设置大一些,让对象在新生代多存活一段时间,每次Minor GC 都要尽可能多的收集垃圾对象,防止或延迟对象进入老年代的机会,以减少应用程序发生Full GC的频率。

        老年代如果使用CMS收集器,新生代可以不用太大,因为CMS的并行收集速度也很快,收集过程比较耗时的并发标记和并发清除阶段都可以与用户线程并发执行。

        方法区大小的设置,1.6之前的需要考虑系统运行时动态增加的常量、静态变量等,1.7只要差不多能装下启动时和后期动态加载的类信息就行。


        代码实现方面,性能出现问题比如程序等待、内存泄漏除了JVM配置可能存在问题,代码实现上也有很大关系:

        避免创建过大的对象及数组:过大的对象或数组在新生代没有足够空间容纳时会直接进入老年代,如果是短命的大对象,会提前出发Full GC。

        避免同时加载大量数据,如一次从数据库中取出大量数据,或者一次从Excel中读取大量记录,可以分批读取,用完尽快清空引用。

        当集合中有对象的引用,这些对象使用完之后要尽快把集合中的引用清空,这些无用对象尽快回收避免进入老年代。

        可以在合适的场景(如实现缓存)采用软引用、弱引用,比如用软引用来为ObjectA分配实例:SoftReference objectA=new SoftReference(); 在发生内存溢出前,会将objectA列入回收范围进行二次回收,如果这次回收还没有足够内存,才会抛出内存溢出的异常。

        避免产生死循环,产生死循环后,循环体内可能重复产生大量实例,导致内存空间被迅速占满。

        尽量避免长时间等待外部资源(数据库、网络、设备资源等)的情况,缩小对象的生命周期,避免进入老年代,如果不能及时返回结果可以适当采用异步处理的方式等。


三、结语

🔥如果文章对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下小老弟,蟹蟹大咖们~ 

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

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

相关文章

通俗易懂的餐厅例子来讲解JVM

餐厅版本 JVM(Java虚拟机)可以想象成一个虚拟的计算机,它能够运行Java程序。为了让你更容易理解,我们可以用一个餐厅的比喻来解释JVM: 菜单(Java源代码): 想象一下,Java…

一文搞懂各种Attention机制

1.各种Attention 最近在重读Transformer论文的过程中,结合其他看过的资料,对各种Attention概念有进一步的了解。回顾最初刚接触时候的迷糊,觉得有必要写一篇文章记录一下对各种attention新的理解。 2.论文中的Transformer架构图 先上经典的…

Python+Appium+Pytest+Allure自动化测试框架-代码篇

文章目录 自动化测试框架工程目录示例测试代码示例结果查看allurepytest编写pytest测试样例的规则pytest conftest.py向测试函数传参 appium启动appium服务代码端通过端口与appium服务通信对设备进行操作在pytest测试用例中调用appium 更多功能 PythonAppiumPytestAllure自动化…

【C++】红黑树的Iterator改造以及mapset的模拟实现与封装

目录 01.红黑树的迭代器 operator: operator*、-> operator、! 02.红黑树的改造 begin和end方法 keyOfValue insert方法 find方法 size方法 clear方法 03.map&set的模拟实现 01.红黑树的迭代器 前面的博客我们介绍了红黑树的底层原理并手撕了一个自己的红…

微信小程序服务通知

项目中用到了小程序的服务消息通知,通知订单状态信息,下边就是整理的一下代码,放到项目中,把项目的小程序appid和小程序的secret写进去,直接运行即可 提前申请好小程序服务信息通知短信模板,代码需要用到模…

linux命令行的艺术

文章目录 前言基础日常使用文件及数据处理系统调试单行脚本冷门但有用仅限 OS X 系统仅限 Windows 系统在 Windows 下获取 Unix 工具实用 Windows 命令行工具Cygwin 技巧 更多资源免责声明 熟练使用命令行是一种常常被忽视,或被认为难以掌握的技能,但实际…

2024年最新版SSL证书

SSL证书行业变动很大,随着操作系统,浏览器新版本不断增加,对SSL证书兼容性要求越来也高,对于安全性也有所提升,主流CA机构根证书及交叉链迎来了换新,这是为了延续下一个20个年的安全计划的提前不如&#xf…

Spark入门到实践

Spark入门到实践 一、Spark 快速入门1.1 Spark 概述1.2 Spark 最简安装1.3 Spark实现WordCount1.3.1 下载安装Scala1.3.2 添加Spark依赖1.3.3 Scala实现WordCount1.3.4 通过IDEA运行WordCount1.3.5 IDEA配置WordCount输入与输出路径1.3.6 通过IDEA运行WordCount1.3.7 查看运行结…

vue、小程序腾讯地图开放平台使用

一、登录账号 腾讯地图API 官方文档: 腾讯位置服务 - 立足生态,连接未来 二、申请秘钥 key 从首页【开发文档】-【微信小程序 SDK】进到微信小程序的开发文档:微信小程序JavaScript SDK | 腾讯位置服务 然后我们根据【Hello World】的提示…

电赛入门之软件stm32keil+cubemx

hal库可以帮我们一键生成许多基本配置,就不需要自己写了,用多了hal库就会发现原来用基本库的时候都过的什么苦日子(笑 下面我们以f103c8t6,也就是经典的最小核心板来演示 一、配置工程 首先来新建一个工程 这里我们配置rcc和sys&…

Elasticsearch开源仓库404 7万多star一夜清零

就在昨晚,有开发者惊奇地发现自己的开源项目 star 数竟然超过了最流行的开源全文搜索引擎 Elasticsearch。发生了什么事?Elasticsearch 竟然跌得比股票还凶 —— 超 7 万 star 的 GitHub 仓库竟然只剩下 200 多。 从社交媒体的动态来看,Elast…

汽车免拆诊断案例 | 2010款起亚赛拉图车发动机转速表指针不动

故障现象  一辆2010款起亚赛拉图车,搭载G4ED 发动机,累计行驶里程约为17.2万km。车主反映,车辆行驶正常,但组合仪表上的发动机转速表指针始终不动。 故障诊断  接车后进行路试,车速表、燃油存量表及发动机冷却温度…

【电商搜索】现代工业级电商搜索技术-亚马逊-经典的Item-to-Item协同推荐算法

【电商搜索】现代工业级电商搜索技术-亚马逊-经典的Item-to-Item协同推荐算法 文章目录 【电商搜索】现代工业级电商搜索技术-亚马逊-经典的Item-to-Item协同推荐算法1. 论文信息2. 算法介绍3. 创新点小结4. 实验效果5. 算法结论6. 代码实现7. 问题及优化方向1. 冷启动问题2. 稀…

Java - 数组实现大顶堆

题目描述 实现思路 要实现一个堆,我们首先要了解堆的概念。 堆是一种完全二叉树,分为大顶堆和小顶堆。 大顶堆:每个节点的值都大于或等于其子节点的值。 小顶堆:每个节点的值都小于或等于其子节点的值。 完全二叉树&#xff…

人工智能与数据安全:Facebook如何应对隐私挑战

在数字时代,数据隐私和安全成为了用户和企业关注的核心问题。作为全球最大的社交媒体平台之一,Facebook面临着日益严峻的隐私挑战。近年来,频繁发生的数据泄露事件和对用户隐私的质疑,使得Facebook在保护用户数据方面倍感压力。为…

2024年ABS分区更新,聚焦管理科学领域新动态

2024学术期刊指南简介 2024年10月30日,英国商学院协会(Chartered Association of Business Schools)发布了最新的《学术期刊指南(Academic Journal Guide)》(以下简称“《指南》”)&#xff0c…

解读!中国人工智能大模型技术白皮书!

近期,中国人工智能协会发布了《中国人工智能大模型技术白皮书》,系统梳理了大模型技术演进,深入探讨关键技术要素,并剖析当前挑战及未来展望。我为大家做了简要总结,并附上原文供深入阅读。 目录 第 1 章 大模型技术概…

深度学习笔记之BERT(一)BERT的基本认识

深度学习笔记之BERT——BERT的基本认识 引言回顾:Transformer的策略回顾:Word2vec的策略和局限性 BERT \text{BERT} BERT的基本理念抽象的双向BERT的预训练策略 预训练与微调 引言 从本节开始,将介绍 BERT \text{BERT} BERT系列模型以及其常…

二:Linux学习笔记(第一阶段)-- Linux命令

目录 Linux注意事项: Linux目录 Linux系统基础命令 1. 文件和目录操作 2. 文件查看和编辑 3. 文件权限和所有权 4. 系统信息 5. 网络命令 6. 文件查找 7. 压缩和解压缩 8. 系统管理 Linux注意事项: 严格区分大小写一切皆文件windows下的程序不…

基于 Java 语言双代号网络图自动绘制系统

基于Java语言双代号网络图自动绘制系统研究与实现 一、摘要 网络计划技术已被广泛应用于工业、农业、国防、科学研究等多个领域中的项目计划与管理,以缩短项目周期,提高资源的利用效率。在网络计划技术中,绘制网络图是网络计划技术的基础工…