福建省晋江市建设局网站,高校网站建设的文章,经典网站设计,卡盟在线自助下单简介#xff1a;
前面两期文章讲了JVM内存模型#xff1a;【JVM详解JVM优化】JVM内存模型-CSDN博客
以及JVM垃圾回收机制#xff1a;【JVM详解JVM优化】JVM垃圾回收机制-CSDN博客 在本篇文章中#xff0c;我们将深入探讨Java虚拟机#xff08;JVM#xff09;…简介
前面两期文章讲了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:NewRatio2 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 objectAnew SoftReference(); 在发生内存溢出前会将objectA列入回收范围进行二次回收如果这次回收还没有足够内存才会抛出内存溢出的异常。 避免产生死循环产生死循环后循环体内可能重复产生大量实例导致内存空间被迅速占满。 尽量避免长时间等待外部资源数据库、网络、设备资源等的情况缩小对象的生命周期避免进入老年代如果不能及时返回结果可以适当采用异步处理的方式等。 三、结语
如果文章对你有帮助的话欢迎关注、点赞、⭐收藏、✍️评论支持一下小老弟蟹蟹大咖们~