4.0.0 com.fan JVMTest 1.0-SNAPSHOT org.apache.maven.plugins maven-shade-plugin 3.2.0 package shade {Mainclass} com.fan.T15_Fu11GC_Problem01 org.apache.maven.plugins maven-compiler-plugin 8 8 jar JVMTest http://maven.apache.org UTF-8 junit junit 3.8.1 test org.apache.tomcat.embed tomcat-embed-core 9.0.58 backport-util-concurrent backport-util-concurrent 3.1
package com.fan;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class T15_Fu11GC_Problem01 {private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50, new ThreadPoolExecutor.DiscardOldestPolicy());public static void main(String[] args) throws Exception {executor.setMaximumPoolSize(50);for (; ; ) {modelFit();Thread.sleep(100);}}private static class CardInfo {BigDecimal price = new BigDecimal(0.0);String name = "张三";int age = 5;Date birihdate = new Date();public void m() {}}private static void modelFit() {List taskList = getAllCardInfo();taskList.forEach(info -> {executor.scheduleWithFixedDelay(() -> {info.m();}, 2, 3, TimeUnit.SECONDS);});}private static List getAllCardInfo() {List taskList = new ArrayList<>();for (int i = 0; i < 100; i++) {CardInfo ci = new CardInfo();taskList.add(ci);}return taskList;}
}
将 JVMTest-1.0-SNAPSHOT.jar 包放到服务器中
java -Xms200M -Xmx200M -XX:+PrintGC -jar JVMTest-1.0-SNAPSHOT.jar
如图,随着时间的推移,GC每隔一段时间回收一次。
1. jps:该命令会显示所有的 java进程,这里我们的测试程序为 4869 jar
2. jinfo 进程号: 该命令显示 对应进程号进程的相关信息
[root@centos142 arthas]# jinfo 4869
Attaching to process ID 4869, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.333-b02
Java System Properties:java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.333-b02
sun.boot.library.path = /usr/local/jdk1.8/jre/lib/amd64
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = :
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level = unknown
sun.java.launcher = SUN_STANDARD
user.country = CN
user.dir = /mnt/arthas
java.vm.specification.name = Java Virtual Machine Specification
java.runtime.version = 1.8.0_333-b02
java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment
os.arch = amd64
java.endorsed.dirs = /usr/local/jdk1.8/jre/lib/endorsed
java.io.tmpdir = /tmp
line.separator = java.vm.specification.vendor = Oracle Corporation
os.name = Linux
sun.jnu.encoding = UTF-8
java.library.path = /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
java.specification.name = Java Platform API Specification
java.class.version = 52.0
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
os.version = 3.10.0-1160.el7.x86_64
user.home = /root
user.timezone =
java.awt.printerjob = sun.print.PSPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
user.name = root
java.class.path = JVMTest-1.0-SNAPSHOT.jar
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = JVMTest-1.0-SNAPSHOT.jar
java.home = /usr/local/jdk1.8/jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.X11.XToolkit
java.vm.info = mixed mode
java.version = 1.8.0_333
java.ext.dirs = /usr/local/jdk1.8/jre/lib/ext:/usr/java/packages/lib/ext
sun.boot.class.path = /usr/local/jdk1.8/jre/lib/resources.jar:/usr/local/jdk1.8/jre/lib/rt.jar:/usr/local/jdk1.8/jre/lib/sunrsasign.jar:/usr/local/jdk1.8/jre/lib/jsse.jar:/usr/local/jdk1.8/jre/lib/jce.jar:/usr/local/jdk1.8/jre/lib/charsets.jar:/usr/local/jdk1.8/jre/lib/jfr.jar:/usr/local/jdk1.8/jre/classes
java.vendor = Oracle Corporation
file.separator = /
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.cpu.isalist = VM Flags:
Non-default VM flags: -XX:CICompilerCount=2 -XX:InitialHeapSize=209715200 -XX:MaxHeapSize=209715200 -XX:MaxNewSize=69730304 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=69730304 -XX:OldSize=139984896 -XX:+PrintGC -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC
Command line: -Xms200M -Xmx200M -XX:+PrintGC
例如,这里我们启动的程序使用的是 -Xms200M -Xmx200M -XX:+PrintGC
3. jstat -[gc] 进程号 [500]:该命令用来统计或跟踪 java 的进程信息。
(1)、动态观察 GC 情况(阅读 GC日志发现频繁GC 、arthas观察、jvisualVM、Jprofiler等)。
[root@centos142 arthas]# jstat -gc 4869S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
8192.0 8192.0 0.0 0.0 50688.0 50040.7 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 12 5.061 5.366
(2)、每500毫秒刷新一次,用来跟踪内存的增长过程
[root@centos142 arthas]# jstat -gc 4869 500S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
8192.0 8192.0 0.0 0.0 50688.0 50551.2 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 21 8.917 9.221
8192.0 8192.0 0.0 0.0 50688.0 50600.3 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 21 8.917 9.221
8192.0 8192.0 0.0 0.0 50688.0 50653.5 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 21 8.917 9.221
8192.0 8192.0 0.0 0.0 50688.0 50653.5 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 21 8.917 9.221
8192.0 8192.0 0.0 0.0 50688.0 50653.5 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 21 8.917 9.221
8192.0 8192.0 0.0 0.0 50688.0 50653.5 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 21 8.917 9.221
8192.0 8192.0 0.0 0.0 50688.0 50655.6 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 21 8.917 9.221
8192.0 8192.0 0.0 0.0 50688.0 50688.0 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 22 8.917 9.221
8192.0 8192.0 0.0 0.0 50688.0 50039.5 136704.0 136606.0 4864.0 4113.3 512.0 446.4 5 0.304 22 9.302 9.606
注意:图形界面用在测试的时候, 压测观察,而不是用在生产环境下定位OOM。
4. jstack 4869 :该命令会显示 所有的线程(线程名、线程编号、线程优先级、操作系统级的优先级、线程的状态、线程的调用堆栈)的信息。如:多个线程的状态一直是 waiting on condition
如何找到哪个线程持有这把锁?
搜索 jstack dump 的信息,找
[root@centos142 arthas]# jstack 4869
"pool-1-thread-45" #52 prio=5 os_prio=0 tid=0x00007fda34290000 nid=0x133d waiting on condition [0x00007fd9e2bea000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000000f82aef40> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1088)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:750)
"pool-1-thread-44" #51 prio=5 os_prio=0 tid=0x00007fda3428e000 nid=0x133c waiting on condition [0x00007fd9e2ceb000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000000f82c4af8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
5. 系统级命令,top、top - Hp 进程号,top:查看当前进程占内存情况、top - Hp 进程号:查看进程号中所有线程的内存、cup情况。
6. jmap 作用1:
a、jmap -histo 进程号: 对当前 jvm 的所有对象进行分析,查看哪些类有多少个对象,占多大字节。
b、jmap -histo 进程号 | head -20 :查看最占内存的前20个对象是哪些。
jmap 作用2:
jmap -dump:format=b,file=20230121.hprof 进程号 :产生一个java的整个堆内存的转储文件,对它进行分析。
注意:jmap是不可以在 生成环境下执行的,会产生一个很严重的后果:jmap会让 jvm 卡死在某个状态,线上系统,内存特别大,jmap执行期间会对进程产生很大影响,甚至卡顿(电商不适合)
1:设定了参数HeapDump,OOM的时候会自动产生堆转储文件(不是很专业,因为多有监控,内存增长就会报警)
2:很多服务器备份(高可用) ,停掉这台服务器对其他服务器不影响
3:在线定位(一般小点儿公司用不到)
4:在测试环境中压测(产生类似内存增长问题,在堆还不是很大的时候进行转储)
1. 使用 top 找出哪个进程占用 cpu 比较高。
2. 使用 top -Hp 进程号,找到这个进程中哪个线程占用 cpu 高。
3. 根据线程编号通过 jstack 查看调用链路。一般分为俩种情况:
a、vm GC
b、业务线程,找业务方法占用高的
4. 如果是 vm GC,查看日志,看看原因是什么。如:访问量压力大(扩容机器)、内存回收不掉。
5. 一般启动项目的时候会设置,当进程出现 OOM后,自动生成dump文件。通过工具对dump文件进行分析。
java -Xms200M -Xmx200M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError java文件或 jar包
以上所有命令,都可以被 arthas 替代,arthas更方便、更全面!,学习arthas地址:
Arthas 入门到实战(一)快速入门_明湖起风了的博客-CSDN博客