【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可以实时观测数据,而且不仅仅可以观测本地进程,还可以观测远程进程。


相关文章
|
12天前
|
运维 Java Shell
手工触发Full GC:JVM调优实战指南
本文是关于Java应用性能调优的指南,重点介绍了如何使用`jmap`工具手动触发Full GC。Full GC是对堆内存全面清理的过程,通常在资源紧张时进行以缓解内存压力。文章详细阐述了Full GC的概念,并提供了两种使用`jmap`触发Full GC的方法:通过`-histo:live`选项获取存活对象统计信息,或使用`-dump`选项生成堆转储文件以分析内存状态。同时,文中也提醒注意手动Full GC可能带来的性能开销,建议在生产环境中谨慎操作。
|
2天前
|
监控 算法 Java
JVM调优-简介(一)
JVM调优-简介(一)
3 0
|
16天前
|
Java
JDK8中JVM堆内存划分
JDK8中JVM堆内存划分
15 0
|
16天前
|
Java 应用服务中间件 Linux
Tomcat 调优及 JVM 参数优化
Tomcat 调优及 JVM 参数优化
|
24天前
|
存储 算法 Java
JVM性能调优:内存模型及垃圾收集算法
JVM性能调优:内存模型及垃圾收集算法
29 0
|
25天前
|
Java Linux
JVM堆内存诊断
JVM堆内存诊断
21 0
|
3天前
|
监控 算法 Java
Java虚拟机(JVM)使用多种垃圾回收算法来管理内存,以确保程序运行时不会因为内存不足而崩溃。
【6月更文挑战第20天】Java JVM运用多种GC算法,如标记-清除、复制、标记-压缩、分代收集、增量收集、并行收集和并发标记,以自动化内存管理,防止因内存耗尽导致的程序崩溃。这些算法各有优劣,适应不同的性能和资源需求。垃圾回收旨在避免手动内存管理,简化编程。当遇到内存泄漏,可以借助VisualVM、JConsole或MAT等工具监测内存、生成堆转储,分析引用链并定位泄漏源,从而解决问题。
12 4
|
5天前
|
算法 Java
Java垃圾回收(Garbage Collection,GC)是Java虚拟机(JVM)的一种自动内存管理机制,用于在运行时自动回收不再使用的对象所占的内存空间
【6月更文挑战第18天】Java的GC自动回收内存,包括标记清除(产生碎片)、复制(效率低)、标记整理(兼顾连续性与效率)和分代收集(区分新生代和老年代,用不同算法优化)等策略。现代JVM通常采用分代收集,以平衡性能和内存利用率。
31 3
|
11天前
|
算法 安全 Java
JVM系列4-垃圾收集器与内存分配策略(二)
JVM系列4-垃圾收集器与内存分配策略(二)
20 0
JVM系列4-垃圾收集器与内存分配策略(二)
|
17天前
|
存储 Java
JVM内存结构(4)
JVM内存结构
15 1