42

深入理解Java虚拟机-如何利用VisualVM对高并发项目进行性能分析

 4 years ago
source link: https://segmentfault.com/a/1190000021442637
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前面在学习JVM的知识的时候,一般都需要利用相关参数进行分析,而分析一般都需要用到一些分析的工具,因为一般使用IDEA,而VisualVM对于IDEA也不错,所以就选择VisualVM来分析JVM性能,这篇文章就介绍一下 如何利用VisualVM进行性能分析 ,以及在分析之前需要知道一些 GC优化的原则GC优化的目的 ,以及 遇到问题时怎么去解决问题的方法

1 为什么需要

开发大型 Java 应用程序的过程中难免遇到内存泄露、性能瓶颈等问题,比如文件、网络、数据库的连接未释放,未优化的算法等。随着应用程序的持续运行,可能会造成整个系统运行效率下降,严重的则会造成系统崩溃。为了找出程序中隐藏的这些问题,在项目开发后期往往会使用性能分析工具来对应用程序的性能进行分析和优化。

VisualVM 是一款免费的性能分析工具。它通过 jvmstat、JMX、SA(Serviceability Agent)以及 Attach API 等多种方式从程序运行时获得实时数据,从而进行动态的性能分析。同时,它能自动选择更快更轻量级的技术尽量减少性能分析对应用程序造成的影响,提高性能分析的精度。

2 如何安装

这里有两种方式:

  • 没有按照IDEA插件

如果没有按照IDEA插件的话,我们需要找到JDK的按照目录bin下找到如下执行程序。

ZfAneqN.png!web

然后双击执行,就会出现界面,如下;

IJNbIrv.png!web

但是,我们一般使用IDEA,所以会使用插件,就是下面这种方式。

  • 按照IDEA插件

先在插件中找到VisualVM安装;

BzUVFnq.png!web

安装了之后,在运行的地方就会多出现两个VisualVM的运行按钮;

uYnuAjN.png!web

这样运行程序之后,就可以自动打开VisualVM程序了。

3 基本介绍

这一部分先对这个工具做一个简要的介绍,看看基本有哪些我们会用到的功能。

在没有添加其他插件的时候,是只有下面几个功能的。

imqimeY.png!web

3.1 概述

NrABzaB.png!web

如上图所示,概述基本上都是我们的 系统属性、运行程序时设置的JVM参数 等信息的展示,所以,这一部分可以让我们查看这些信息。

3.2 监视

jyI3iuB.png!web

监视这个界面的功能还是很有作用的,可以看到 cup运行情况、堆的使用情况、类的情况以及线程的动态情况

因此,我们可以利用这个界面查看cpu情况好不好,更重要的是,我们可以查看堆的使用情况,这对于我们分析JVM还是非常重要的。

3.3 线程

636Rbqr.png!web

如上图所以,可以看到所有的线程的情况,是 运行、休眠、等待、驻留、监视 等情况。

注意,以上这些都不是关键,关键是VisualVM中还有一个很重要的功能,可以添加插件获取更多的功能。

3.4 插件添加

正是因为有了插件的扩展功能,所以这个工具才如此强大,VisualVM可以做到以下:

  • 显示虚拟机进程以及进程的配置、环境信息、jps、jinfo。
  • 监视应用程序的cpu、GC、堆、方法区以及线程的信息(jstat、jstack)。
  • dump以及分析堆转存储快照(jmap、jhat)。
  • 还有很多其他的功能。

在工具->找到可用插件,安装即可。

mAJ7vuq.png!web

下一部分我们就利用已经安装的插件 Visual GC 进行分析。

4 利用 Visual GC 分析虚拟机内存区域

这部分会用到一些Java虚拟机的一些基础知识,所以,查看这部分之前,请先查看这篇文章:。

qIbuuiR.png!web

在这个界面分为以下几个部分。

  • space(Metaspace(元数据)、Old老年代、新生代(Eden、S0、S1))
  • Graphs(Compile Time(编译时间)、Class Loader Time(类加载时间)、GC Time(垃圾收集时间)、Eden Space、Survivor 0、Survivor 1、Old Gen、Metaspace)
  • Histogram(Parameters参数设置)

那么知道这些参数之后,怎么去分析虚拟机到底运行是好是坏呢,这个时候,我们需要了解一些Java虚拟机基础的优化知识。

首先,需要了解一些 GC优化的原则

  • 多数的Java应用不需要在服务器上进行GC优化;
  • 多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题;
  • 在应用上线之前,先考虑将机器的JVM参数设置到最优(最适合);
  • 减少创建对象的数量;
  • 减少使用全局变量和大对象;
  • GC优化是到最后不得已才采用的手段;
  • 在实际使用中,分析GC情况优化代码比优化GC参数要多得多;

另外,我们需要知道我们 GC优化的目的

  • 将转移到老年代的对象数量降低到最小;
  • 减少full GC的执行时间;

一般,我们需要执行的有以下几点;

  • 减少使用全局变量和大对象;
  • 调整新生代的大小到最合适;
  • 设置老年代的大小为最合适;
  • 选择合适的GC收集器;

至于怎么算合适,后面我会通过一个实例讲解。

其实,如果想要知道更多 JVM内存分配和回收策略的原理 ,可以查看这篇文章: JVM内存分配和回收策略的原理

一般我们执行了我们的程序之后,接下来就是需要 查看GC的状态 了,接着 分析结果 ,判断 是否需要进行优化

一般如果达到以下的 指标 ,就不需要进行GC了。

  • Minor GC 执行时间不到 50msMinor GC 执行不频繁,约 10 秒一次;
  • Full GC 执行时间不到 1sFull GC 执行频率不算频繁,不低于 10 分钟1次;

实例 1

我们先看一个GC状态需要优化的例子,在这个实例中,我们给堆分配的最大最小的值都是 64M (很小的堆大小)。

GC状态差情况分析

/**
 * VM Args:-Xms64m -Xmx64m -XX:+HeapDumpOnOutOfMemoryError
 * @author 欧阳思海
 */
public class HeapTest {

    static class StaticObject {
    }

    public static void main(String[] args) {
        List<StaticObject> list = new ArrayList<StaticObject>();
        int i = 1;

        //不断的向堆中添加对象
        while (true) {
            list.add(new StaticObject());
            i++;
            System.out.println(i);
            System.out.println(list.size());
        }
    }
}

7v2Y7fm.png!web

由于分配的堆内存太小,所以导致,堆溢出。

接着我们查看一下 Visual GC 的监视情况。

  • 监视界面情况

7RJfAza.png!web

我们可以从堆的使用情况看出,基本已经使用完。

  • Visual GC监视情况

MrArM3v.png!web

从上图可知,在短短的运行时间中, Eden进行了49次GC,虽然时间短,但是能说明一个问题,新生代堆内存分配的空间太小,导致频繁GC

同时,Old老年代也进行了33次GC,虽然运行时间也在不需要优化的范围内,而且从Survivor可以看出,基本没有GC,说明这些都是大对象,直接进入到了Old老年代,导致GC频繁。

所以,我们需要进行的优化就是 加大新生代和老年代堆内存的大小,同时减少大对象的产生

参数优化分析

我们将VM参数改为: -Xms512m -Xmx512m -Xmn128m -XX:+HeapDumpOnOutOfMemoryError ,运行大概 5分钟 再次查看结果。

BRfaiyq.png!web

首先没有出现堆内存溢出。

  • 监视情况

aQV7Frr.png!web

加大了堆内存,所以堆内存没有出现问题。

  • Visual GC监视情况

ya2UZvE.png!web

加大了堆内存之后, Eden新生代进行了66次GC,使用时间3.381s基本满足要求(执行时间不到50ms,Minor GC执行不频繁,约10秒一次),同时老年代old进行了2次GC,使用时间4.127s,这里还是有待优化的,不太满足优化要求。

  • dump文件分析

MVJFvuV.png!web

点击 堆 dump 这个按钮就会生成 dump文件,我们可以分析类及对象的一些情况。

RrAzeaB.png!web

分析之后发现, StaticObject对象大多,没有进行GC ,问题主要在这里,所以,下一步需要解决这个问题。

通过以上分析可以说明一个问题,加大了堆内存之后,新生代和老年代的GC情况大大的改善了,但是还有 大对象的问题 ,所以还有待优化。

修改大对象,进行GC

修改程序,如下:

/**
 * VM Args:-Xms512m -Xmx512m -Xmn128m -XX:+HeapDumpOnOutOfMemoryError
 *
 * @author 欧阳思海
 */
public class HeapTest {

   /* static class StaticObject {
    }*/

    public static void main(String[] args) {
        int i = 1;

        while (true) {
            i++;
            System.out.println(i);
        }

    }
}
  • 监视情况

QRjAJfq.png!web

堆一直运行良好。

  • Visual GC监视情况

Mvu2Urq.png!web

这次相对于上次相比,老年代的情况已经改善了,没有GC,说明大对象不存在了。

通过上面的分析跟优化,就满足GC的需求了,不需要再优化了。

Java虚拟机深入理解系列全部文章更新中...

5 总结

通过上面的分析及使用,VisualVM基本的使用以及如何利用VisualVM进行Java虚拟机优化相信你已经掌握了,如果还想了解更过关于Java虚拟机的知识及优化文章,请看本系列的其他文章。

1、 原创不易 ,老铁,文章需要你的 点赞 让更多的人看到,希望能够帮助到大家!

2、文章有不当之处,欢迎指正,如果喜欢微信阅读,你也可以关注我的 微信公众号 好好学java ,公众号已有 6W 粉丝,回复: 1024 ,获取公众号的大礼包,公众号长期发布 Java 优质系列文章 ,关注我们一定会让你收获很多!

BBZbUv2.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK