JDK に付属の JVM 分析ツール

メモリ オーバーフロー、適切な名シーン;

1.事業の背景

分散アーキテクチャのファイル サービスでは、多数の IO ストリーム操作が関係するため、JVM 関連の例外、特にメモリ オーバーフローの問題が発生しやすくなります。

最新バージョンのイテレーションでは、実際の業務処理シナリオは上記とほぼ同じですが、ファイル サービスにバッチ処理アクションが追加されたことにより、長い間隠されていたバグが直接目覚め、これが最も重要です。共通メモリのオーバーフロー。

問題の原因: Word 文書は、コンテンツの認識が完了した後、pdf ファイルに変換され、その後、ページが一連の写真に分割される. この複雑で長いプロセスでは、配列コンテナーではありません.破壊されました;

解決策: JVM のダンプ ファイルを分析し、OOM 問題の根本原因を突き止め、ファイル サービスの異常ログ分析を組み合わせ、リソースの解放アクションを追加して問題を解決します。

2. Jdk-Bin ディレクトリ

かなりの数の初心者にとって、JVMの問題はすべて無知なバグです. 実際には、このような考え方は必要ありません. 職場での数年間の開発経験から、JVMの問題は大まかに分けることができます. 2 つのタイプ:

  • 開発のための簡単なソリューション: メモリ リソースをアップグレードしたり、割り当てを調整したり、関連するリソースを管理および解放するようにプログラムを最適化したりすることができます。これは最も一般的に使用される方法です。
  • 開発への簡単な解決策: 経験不足のため、プログラムの主要なバグが原因で JVM 例外が発生し、それが一連​​の連鎖反応を引き起こします.この種のリバウンドはジェダイではなく、鶏の羽だけです;

従来の JVM 例外を解決する場合、通常は JDK の基本ツールを使用して問題の場所を特定し、問題を分析して解決しますが、これらには基本ツールの熟練した使用が必要であり、多くの JDK 独自の機能はしばしば無視されます。 ;

jdk の bin ディレクトリには、JVM の分析に使用できる多くの組み込みツールがあります。

上記はjdk1.8をベースにしたディレクトリであり、開発でよく使うコマンドがたくさんあります.マイクロサービスの起動と運用に焦点を当て、JDKベースのJVMツールの使い方を見てみましょう;

3. コマンドライン ツール

1.jpsコマンド

jps : 仮想マシン プロセス ステータス ツール, このコマンドは、Java 環境のデプロイとサービスの起動の表示でよく使用されます. まず、ファサード マイクロサービスをローカルで起動し、次にコマンド ラインでクエリを実行します。

  • jps: コマンドのデフォルトの出力は、プロセス ID とアプリケーションのメイン クラスの名前です。
  • -l: プロセス ID とアプリケーションのメイン クラスのフル パスを出力します。
  • -v:输出向jvm传递的参数,此处展示为idea中显式配置的VM-options参数,其他内容自行查看即可;
  • -m:输出向main方法传递的参数,服务启动前可以在idea的Program-arguments配置;
$ jps
1281 FacadeApp

$ jps -l
1281 com.explore.facade.FacadeApp

$ jps -v
1281 FacadeApp -Xms128m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m

$ jps -m
1281 FacadeApp hello,main-method
复制代码

2、jinfo命令

jinfo:在命令后面带pid进程号,可以输出指定进程的配置信息,在应用启动时通常不会指定过多的配置参数,就可以使用该命令查询很多参数的默认值;该命令还可以在运行时动态调整部分参数,只是很少被使用;

$ jinfo 1281            # 只粘贴个别参数
Java System Properties: # 系统参数
    java.runtime.version=1.8.0_144-b01
    file.encoding=UTF-8
    sun.java.command=com.explore.facade.FacadeApp hello,main-method
    
VM Flags:               # 虚拟机参数
    -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=268435456 -XX:MaxNewSize=267911168
    
VM Arguments:           # 运行时参数
    jvm_args: -Xms128m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m
    java_command: com.explore.facade.FacadeApp hello,main-method

$ jinfo -sysprops 1281  # 只输出【Java System Properties】参数

$ jinfo -flags 1281     # 只输出【VM Flags】参数
复制代码

3、jstat命令

jstat:以指定的频率输出JVM的监控指标,下述命令输出内存占用和GC相关信息,每隔3秒输出一次,连续打印5次;由于这里只是启动一个简单的微服务,没有执行业务逻辑,所以各项指标比较平稳;

$ jstat -gcutil 1281 3000 5
S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT   
0.00   0.00  57.97  64.16  92.82  88.75    3    0.028     9    0.516     -        -    0.544
0.00   0.00  57.97  64.16  92.82  88.75    3    0.028     9    0.516     -        -    0.544
复制代码

该命令是比较常用的,这里各项指标的统计逻辑,在tools.jar包中有jstat_options参考文档,相对路径sun/tools/jstat/resources/目录下;

option gcutil {
  column {
    header "^S0^"	/* Survivor 0 Space - Percent Used */
    data (1-((sun.gc.generation.0.space.1.capacity - sun.gc.generation.0.space.1.used)/sun.gc.generation.0.space.1.capacity)) * 100
  }
  column {
    header "^S1^"	/* Survivor 1 Space - Percent Used */
    data (1-((sun.gc.generation.0.space.2.capacity - sun.gc.generation.0.space.2.used)/sun.gc.generation.0.space.2.capacity)) * 100
  }
  ......
}
复制代码

4、jstack命令

jstack:输出指定进程当前时刻在JVM中的线程信息,为了清楚的展示其效果,在服务启动时创建线程死锁,然后通过该命令就会把发生死锁的线程打印出来,通过输出可以发现两条互相等待的线程信息;

$ jstack 1281
Found one Java-level deadlock:
=============================
"test-thread-02":
  waiting for ownable synchronizer 0x00000007b00a35d0, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "test-thread-01"
"test-thread-01":
  waiting for ownable synchronizer 0x00000007b00a35a0, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "test-thread-02"

Java stack information for the threads listed above:
===================================================
"test-thread-02":
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007b00a35d0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"test-thread-01":
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007b00a35a0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

Found 1 deadlock.
复制代码

5、jmap命令

jmap:可以输出指定进程的内存中对象映射信息,或者堆的关键信息、内存的使用统计、GC算法、配置、类的实例信息及内存占用等,该命令在解决JVM问题时也经常使用;

$ jmap 1281

$ jmap -heap 1281
Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 536870912 (512.0MB)
   
Heap Usage:
    PS Young Generation
    Eden Space:
    From Space:
    To Space:
    PS Old Generation

$ jmap -histo:live 1281
 num     #instances         #bytes  class name
----------------------------------------------
1311:             1             32  com.explore.facade.FacadeApp$$EnhancerBySpringCGLIB$$313d9e3
复制代码

四、可视化工具

1、jconsole

Java内置的JVM性能监控工具,在熟悉上述的命令行工具之后,对于该可视化工具的使用不会太陌生,在命令中可以查看到的默认参数或者应用自定义配置,在该工具中也可以找到,并且以图形化的方式呈现;

$ jconsole  # 通过该命令会唤起jconsole界面
复制代码

这里选择线程一栏,可以直观的看到线程数量的变化曲线,也可以在下方查看某个线程的具体信息,并且可以通过检测死锁功能,发现在服务中创建的test-thread-01和test-thread-02两条线程;

2、visualvm

VisualVM作为解决JVM问题的常用工具,集成的功能丰富且强大,此处通过Idea插件的方式启动FacadeApp微服务,在进程主页可以看到自定义的配置,线程一栏因为检测到死锁直接给到异常提示;

在监视一栏可以通过【堆dump】查看详细的信息,可以查看类的实例数和大小,并且完成了结果排序和占用统计;此处信息在定位和解决JVM问题时非常重要;

对于JVM的监控工具来说,其能力与常用的命令行语法差异很小,并且这些命令在jdk中tools.jar包也可以找到其对应的类,对于一些更高级的监控平台来说,例如Kuboard、Skywalking等,也对这些底层能力做了集成,其原理应该也是大同小异。

五、参考源码

编程文档:
https://gitee.com/cicadasmile/butte-java-note

应用仓库:
https://gitee.com/cicadasmile/butte-flyer-parent
复制代码

おすすめ

転載: juejin.im/post/7158238203537784868