【JVM调优实战100例】03——JVM堆调优四例(上)

简介: 文章目录6.堆6.1 堆的特点6.2 堆内存溢出问题6.3 代码内存性能影响的评估6.4 多次垃圾回收内存占用仍很高问题的排查

6.堆

6.1 堆的特点

使用new关键字创建的对象都会使用堆。

特点:

  • 线程共享,堆中的对象需要考虑线程安全问题。
  • 具有垃圾回收机制。

6.2 堆内存溢出问题

堆中具有垃圾回收机制,但是垃圾回收的前提是堆中的对象不再被引用(实际上,回收引用的算法是根可达算法,后面会讲述,这里的表述是不准确的),因此如果我们有过多无法被回收的对象,就可能导致内存溢出。

public class MemoryOverFlow {
    public static void main(String[] args) {
        int i = 0;
        String a = "hello";
        List list = new ArrayList(); // 直到catch代码块执行,一直被使用
        try {
            while (true) {
                list.add(a);
                a = a + a;
                i++;
            }
        } catch (Throwable e) { //使用Throwable,如果使用Exception包不住Error,i无法被打印出来
           e.printStackTrace();
           System.out.println(i);
        }
    }
}

出现OutOfMemoryError

java.lang.OutOfMemoryError: Overflow: String length out of range
        at java.base/java.lang.StringConcatHelper.checkOverflow(StringConcatHelper.java:57)
        at java.base/java.lang.StringConcatHelper.mix(StringConcatHelper.java:138)
        at java.base/java.lang.StringConcatHelper.simpleConcat(StringConcatHelper.java:420)
        at MemoryOverFlow.main(MemoryOverFlow.java:12)
28

另:参数-Xmx 可以设置jvm内存空间大小,排查堆内存问题时可以将其设置得比较小(如8m),更容易暴露出内存溢出问题。设置方法:点击build and run同行的modify options->add vm options.

6.3 代码内存性能影响的评估

工作中编写了一段代码,如何去判断一段代码对于内存性能的影响呢?可以借助如下工具。


jps 查看系统有哪些java进程


jmap 查看某一时刻堆内存的占用情况


jconsole 多功能实时监测工具


通过下面的demo来演示。

public class jvmdemo {
  public static void main(String[] args) throws InterruptedException {
        System.out.println("1....."); //输出提示,方便进行Heap Dump
        Thread.sleep(60000); //给30s时间用于Heap Dump
        byte [] arr = new byte[1024 * 1024 * 10];
        System.out.println("2.......");
        Thread.sleep(60000);
        arr = null;
        System.gc();
        System.out.println("3......");
        Thread.sleep(100000L);
  }
}

当输出1…后,先执行jps查看jvmdemo对应的pid


💡 tip:如果您是windows系统,jps无返回结果,可以参考博客


Windows中jps命令无法查看java进程问题_无数_mirage的博客-CSDN博客_windows 查看java进程


结果如下。

执行jmap -heap xxx(pid)查看此时堆内存占用情况。


💡 tip:


如果执行jmap报错。

Error: -heap option used
Cannot connect to core dump or remote debug server. Use jhsdb jmap instead

是因为jdk8之后的版本之前的jmap -heap xxx(pid)命令不可再使用。可以改用命令jhsdb jmap --heap --pid xxx.


在提示信息输出1,2,3后分别进行三次操作得到的结果如下。

Heap Usage:
G1 Heap:
   regions  = 2034
   capacity = 8531214336 (8136.0MB)
   used     = 0 (0.0MB)
   free     = 8531214336 (8136.0MB)
   0.0% used
G1 Young Generation:
Eden Space:
   regions  = 0
   capacity = 29360128 (28.0MB)
   used     = 0 (0.0MB)
   free     = 29360128 (28.0MB)
   0.0% used
Survivor Space:
   regions  = 0
   capacity = 0 (0.0MB)
   used     = 0 (0.0MB)
   free     = 0 (0.0MB)
   0.0% used
G1 Old Generation:
   regions  = 0
   capacity = 507510784 (484.0MB)
   used     = 0 (0.0MB)
   free     = 507510784 (484.0MB)
   0.0% used
Heap Usage:
G1 Heap:
   regions  = 2034
   capacity = 8531214336 (8136.0MB)
   used     = 12582912 (12.0MB)
   free     = 8518631424 (8124.0MB)
   0.14749262536873156% used
G1 Young Generation:
Eden Space:
   regions  = 0
   capacity = 29360128 (28.0MB)
   used     = 0 (0.0MB)
   free     = 29360128 (28.0MB)
   0.0% used
Survivor Space:
   regions  = 0
   capacity = 0 (0.0MB)
   used     = 0 (0.0MB)
   free     = 0 (0.0MB)
   0.0% used
G1 Old Generation:
   regions  = 3
   capacity = 507510784 (484.0MB)
   used     = 12582912 (12.0MB)
   free     = 494927872 (472.0MB)
   2.479338842975207% used
Heap Usage:
G1 Heap:
   regions  = 2034
   capacity = 8531214336 (8136.0MB)
   used     = 673872 (0.6426544189453125MB)
   free     = 8530540464 (8135.357345581055MB)
   0.007898898954588403% used
G1 Young Generation:
Eden Space:
   regions  = 0
   capacity = 8388608 (8.0MB)
   used     = 0 (0.0MB)
   free     = 8388608 (8.0MB)
   0.0% used
Survivor Space:
   regions  = 0
   capacity = 0 (0.0MB)
   used     = 0 (0.0MB)
   free     = 0 (0.0MB)
   0.0% used
G1 Old Generation:
   regions  = 1
   capacity = 8388608 (8.0MB)
   used     = 673872 (0.6426544189453125MB)
   free     = 7714736 (7.3573455810546875MB)
   8.033180236816406% used

重点查看uesd这一项,可以看到代码中内存的变化过程,这里JVM version 是16.0.2+7-67,不同版本可能略有差异。


使用jconsole可以实时观测数据,而且不仅仅可以观测本地进程,还可以观测远程进程。


目录
打赏
0
0
0
0
4
分享
相关文章
JVM实战—10.MAT的使用和JVM优化总结
本文详细探讨了JVM内存管理与性能优化的关键问题。首先分析了线上大促活动引发的老年代内存泄漏及频繁FGC问题,通过MAT工具定位到本地缓存未正确处理的原因,并提出使用Ehcache等框架解决。接着讨论了百万级数据误处理导致的频繁FGC案例,深入剖析String.split()方法在特定JDK版本下的内存消耗问题,并给出多线程并发处理大数据量的优化建议。文章还总结了JVM运行原理、GC机制以及YGC和FGC的触发条件,明确了正常系统GC频率指标。最后提供了JVM性能优化的整体思路,包括新系统开发时的参数预估、压测后的调整策略以及线上系统的监控方法,同时列举了常见的FGC原因及对应解决方案。
139 79
JVM实战—10.MAT的使用和JVM优化总结
JVM实战—11.OOM的原因和模拟以及案例
本文详细探讨了Java系统中内存溢出(OutOfMemory,简称OOM)问题的成因与解决方法。首先分析了线上系统因OOM挂掉的常见场景及处理思路,接着深入讲解了JVM中可能发生OOM的三大区域:Metaspace(类信息存储区)、栈内存(线程执行方法时使用)和堆内存(对象存储区)。针对每个区域,文章通过具体代码示例模拟了内存溢出的情况,如动态生成过多类导致Metaspace溢出、无限递归调用引发栈内存溢出以及高负载下堆内存不足等问题。最后结合实际案例,如大数据处理系统因Kafka故障未正确处理数据缓存而导致OOM,以及无限循环调用或未缓存动态代理类引发的问题,给出了预防和改进措施。
137 64
JVM实战—11.OOM的原因和模拟以及案例
JVM实战—13.OOM的生产案例
本文详细探讨了多种线上系统中引发OOM(内存溢出)问题的原因及排查方法。内容涵盖:1)每秒仅上百请求的系统因RPC超时时间设置过长导致QPS激增而OOM;2)Jetty服务器NIO机制因堆外内存管理不当引发内存溢出;3)微服务架构下RPC调用因类定义不一致导致超大byte[]数组占用内存;4)SQL语句缺少WHERE条件查询大量数据引发OOM;5)日志分析系统因堆内存不足与递归操作耗尽内存;6)类加载器过多导致内存使用过高被OS杀死进程;7)数据同步系统频繁OOM的排查与解决;8)总结JVM参数优化、GC问题定位及OOM分析方法。
JVM实战—13.OOM的生产案例
JVM实战—9.线上FGC的几种案例
本文详细探讨了JVM性能优化中的几个关键案例与问题。首先分析了如何优化每秒十万QPS的社交APP,通过增加Survivor区大小和优化内存碎片解决频繁Full GC的问题。接着讨论了垂直电商后台系统FGC的深度优化,定制JVM参数模板以降低GC频率。还探讨了不合理设置JVM参数导致频繁FGC的情况,并提出了解决方案。此外,针对线上系统每天数十次FGC的问题,定位到大对象是主要原因,并通过调整新生代大小等参数优化。同时,分析了电商大促活动中因System.gc()调用导致系统卡死的现象,建议禁用显式GC。
JVM实战—9.线上FGC的几种案例
JVM实战—12.OOM的定位和解决
本文详细探讨了JVM内存管理中的常见问题及其解决方案,包括如何监控和报警系统的OOM异常、在内存溢出时自动Dump内存快照、解决Metaspace区域内存溢出、栈内存溢出(StackOverflowError)以及堆内存溢出(OutOfMemoryError: Java heap space)。针对每种情况,文章提供了具体的解决思路、示例代码、GC日志分析及内存快照分析方法。通过搭建系统监控体系、调整JVM参数和使用工具如MAT,可以有效定位和解决各类内存问题,优化系统性能并避免崩溃风险。
JVM实战—12.OOM的定位和解决
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
130 29
JVM简介—1.Java内存区域
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
678 166
JVM实战—2.JVM内存设置与对象分配流转
本文详细介绍了JVM内存管理的相关知识,包括:JVM内存划分原理、对象分配与流转、线上系统JVM内存设置、JVM参数优化、问题汇总。
JVM实战—2.JVM内存设置与对象分配流转
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
882 1