Estouro de memória, cena famosa própria;
1. Histórico de negócios
Para serviços de arquivo em uma arquitetura distribuída, devido ao grande número de operações de fluxo de E/S envolvidas, é fácil causar exceções relacionadas à JVM, especialmente o problema de estouro de memória;
Na iteração da versão mais recente, o cenário real de processamento de negócios é quase o mesmo que o acima. Devido à adição de ações de processamento em lote no serviço de arquivos, o bug que estava oculto por muito tempo é despertado diretamente, que é o mais estouro de memória comum;
A causa do problema: Depois que o documento do word conclui o reconhecimento do conteúdo, ele é convertido em um arquivo pdf e, em seguida, a página é dividida em um conjunto de imagens. Nesse processo complexo e longo, há um contêiner de matriz que não é destruído;
Solução: analise o arquivo dump da JVM, localize a causa raiz do problema OOM, combine a análise de log anormal do serviço de arquivo e inclua a ação de liberação do recurso para solucionar o problema;
2. Diretório Jdk-Bin
Para um número considerável de novatos, ver os problemas da JVM são todos bugs ignorantes. Na verdade, esse tipo de mentalidade não é necessário. A partir da experiência de desenvolvimento de vários anos no local de trabalho, os problemas da JVM podem ser divididos em dois tipos:
- Solução fácil para desenvolvimento: Você pode atualizar recursos de memória ou ajustar alocação, ou otimizar programas para gerenciar e liberar recursos relacionados, que é o método mais utilizado;
- Solução fácil para o desenvolvimento: Por falta de experiência, grandes bugs no programa levam a exceções de JVM, que por sua vez causam uma série de reações em cadeia.Esse tipo de rebote não será Jedi, mas apenas penas de galinha;
Ao resolver exceções convencionais da JVM, você geralmente confia nas ferramentas básicas do JDK para concluir a localização do problema, de modo a analisar e resolver o problema, mas elas exigem o uso qualificado das ferramentas básicas e muitos recursos próprios do JDK são frequentemente ignorados. ;
No diretório bin do jdk, existem muitas ferramentas internas que podem ser usadas para analisar a JVM;
O acima é um diretório baseado em jdk1.8 , e há muitos comandos que são frequentemente usados em desenvolvimento Vamos focar na inicialização e operação de um microsserviço e vamos dar uma olhada no uso de ferramentas JVM baseadas em JDK;
3. Ferramentas de linha de comando
1. comando jps
jps : ferramenta de status do processo de máquina virtual, este comando é frequentemente usado na implantação do ambiente Java e visualização de inicialização do serviço.Primeiro, inicie um microsserviço de fachada localmente e, em seguida, execute a consulta na linha de comando;
jps
: A saída padrão do comando é o ID do processo e o nome da classe principal do aplicativo;-l
: Emita o ID do processo e o caminho completo da classe principal do aplicativo;-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
复制代码