博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OOM、调优工具、调优实战
阅读量:2289 次
发布时间:2019-05-09

本文共 6679 字,大约阅读时间需要 22 分钟。

调优工具

 

1、jps

 

-q:只显示Java进程的ID

image.png


-m:输出Java进程的ID + main函数所在类的名词 + 传递给main函数的参数

image.png


-l:输出Java进程的ID + main函数所在类的全限定名(包名 + 类名)

image.png


-v:输出Java进程的ID + main函数所在类的名称 + 传递给JVM的参数

应用:可通过此方式快速查看JVM参数是否设置成功

image.png


-V、hostid基本用不到,这里就不做介绍了,感兴趣的同学可以自行百度学习。

 

源码在哪

 

\openjdk\jdk\src\share\classes\sun\tools\jps\

 

纯Java编写的

 

如何识别Java进程

 

jps输出的信息全是Java进程的信息,是如何做到的?

 

Java进程在创建的时候,会生成相应的文件,进程相关的信息会写入该文件中。Windows下默认理解是C:\Users\username\AppData\Local\Temp\hsperfdata_username,Linux下默认路径是/tmp/hsperfdata_username

image.png

2、jstate

 

Hotspot自带的工具,通过该工具可实时了解某个进程的class、compile、gc、memory的相关信息。具体可通过该工具查看哪些信息可通过jstat -options查看

 

image.png

 

为什么说是实时呢,因为底层实现是mmap,及内存映射文件

 


jstat输出的这些值从哪来的

 

PerfData文件

Windows下默认理解是C:\Users\username\AppData\Local\Temp\hsperfdata_username

Linux下默认路径是/tmp/hsperfdata_username

 


PerfData文件

 

1、文件创建

 

取决于两个参数

 

-XX:-/+UsePerfData

默认是开启的

关闭方式:-XX:-UsePerfData。如果关闭了,就不会创建PerfData文件

 

-XX:-/+PerfDisableSharedMem(禁用共享内存)

默认是关闭的,即支持内存共享。如果禁用了,依赖于PerfData文件的工具就无法正常工作了

 

2、文件删除

 

默认情况下随Java进程的结束而销毁

 

3、文件更新

 

-XX:PerfDataSamplingInterval = 50ms

即内存与PerfData文件的数据延迟为50ms

 


 

纯Java编写

\openjdk\jdk\src\share\classes\sun\tools\jstat\Jstat.java

 

3、jinfo

 

4、jstack

 

5、jmap

 

6、jconsole

 

7、visualVM

 

8、arthas

 

Java Agent

 

1、命令行

2、attach

 

参考文章:

 

实战

 

1、统计线程数

 

jstack -l 6972 | grep 'java.lang.Thread.State' | wc -l

 

2、检测死锁

 

可使用jstack、jconsle、visualVM

 

image.png

 

3、CPU占用过高

 

  1. 定位到占用CPU最高的进程

image.png

  1. 定位到目前占用CPU最高的线程ID
top -H -p 6290

image.png

 

线程ID由十进制转成十六进制,用Python

image.png

 

  1. 定位线程
jstack 6290(进程ID)|grep 18a1(线程ID,十六进制) -A 30

 

1、自己想案例模拟OOM并思考如何调优

      1)、方法区

        参数调整:-XX:MetaspaceSize=10M  -XX:MaxMetaspaceSize=10M

        

import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** * Created by smoner on 2020/8/23. */public class MetaspaceFlowTest {    public static void main(final String[] args) {        while (true){            try {                Thread.sleep(10);            } catch (InterruptedException e) {                e.printStackTrace();            }            Enhancer enhancer = new Enhancer();            enhancer.setSuperclass(MetaspaceFlowTest.class);            enhancer.setUseCache(false);            enhancer.setCallback(new MethodInterceptor() {                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {                    return methodProxy.invokeSuper(o,args);                }            });            System.out.println("running......");            enhancer.create();        }    }}

GC日志:

GC日志:[GC (Metadata GC Threshold)  75278K->3488K(375296K), 0.0051576 secs][Full GC (Metadata GC Threshold)  3488K->3334K(216064K), 0.0200447 secs][GC (Last ditch collection)  3334K->3334K(216064K), 0.0011828 secs][Full GC (Last ditch collection)  3334K->1688K(310272K), 0.0253545 secs]

调优原则:

1、最大、最小设置成一样大

2、程序运行起来后,通过visualVM、arthas查看占用了多少内存,向上调优,预留20%以上的空间

      2)、堆

import java.util.ArrayList;import java.util.List;/** * Created by smoner on 2020/8/24. */public class HeapOverFlowTest {    int[] intArray = new int[10];    public static void main(String[] args) {        List
objs = new ArrayList
(); for (;;){ try { Thread.sleep(1); }catch (Exception e){ e.printStackTrace(); } objs.add(new HeapOverFlowTest()); } }}

 

GC日志:

[GC (Allocation Failure) [PSYoungGen: 1344K->320K(2048K)] 7894K->7118K(9216K), 0.0071516 secs] [Times: user=0.01 sys=0.00, real=0.00 secs][GC类型 (GC原因) [新生代垃圾收集器: gc前新生代的内存使用情况->gc后新生代的内存使用情况(新生代总内存)] gc前堆内存的使用情况->gc后堆内存的使用情况(堆总内存), gc耗时] [Times: gc阶段用户空间耗时 gc阶段内核空间耗时, gc阶段实际耗时][Full GC (Ergonomics) [PSYoungGen: 320K->0K(2048K)] [ParOldGen: 6798K->5930K(7168K)] 7118K->5930K(9216K), [Metaspace: 9296K->9233K(1058816K)], 0.6733958 secs] [Times: user=1.76 sys=0.00, real=0.68 secs][GC类型 (GC原因) [新生代垃圾收集器: gc前新生代的内存使用情况->gc后新生代的内存使用情况(新生代总内存)] [老年代垃圾收集器: gc前老年代的内存使用情况->gc后老年代的内存使用情况(新生代总内存)] gc前堆内存的使用情况->gc后堆内存的使用情况(堆总内存), [Metaspace: gc前元空间的内存使用情况->gc后元空间的内存使用情况(元空间总内存)], gc耗时] [Times: gc阶段用户空间耗时 gc阶段内核空间耗时, gc阶段实际耗时]

调优原则

1、预留30%以上的空间

2、周期性看日志,重点关注full gc频率

      3)、虚拟机栈

public class StackOverFlowTest {    private int val = 0;    private String s = null;    private String s2 = null;    public void test(){        val++;        s = ""+val+"";        s2 = ""+val+""+"-";        test();    }    public static void main(String[] args) {        StackOverFlowTest test = new StackOverFlowTest();        try {            test.test();        }catch (Throwable e){            e.printStackTrace();            System.out.println(test.val);        }    }}

参数

-Xss300k

栈大小相同,栈深度不同,为什么?

       栈上分配,轻量级锁

 

2、死锁、CPU占用过高问题排查,自己实际一遍

1) 死锁实例

public class LockTest {    public static void main(String[] args) {        System.out.println("main start ;");        ReentrantLock lock = new ReentrantLock();        ReentrantLock lock2 = new ReentrantLock();        Thread thread1 = new Thread() {            @Override            public void run() {                System.out.println(Thread.currentThread().getName()+"  start");                lock.lock();                try {                    System.out.println(Thread.currentThread().getName()+"  sleep");                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                lock2.lock();                lock.unlock();                System.out.println(Thread.currentThread().getName()+"  end");            }        };        Thread thread2 = new Thread() {            @Override            public void run() {                System.out.println(Thread.currentThread().getName()+"  start");                lock2.lock();                try {                    Thread.sleep(100);                } catch (InterruptedException e) {                    e.printStackTrace();                }                lock.lock();                try {                    sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                lock.unlock();                lock2.unlock();            }        };        System.out.println("sub thread start ;");;        thread1.start();        thread2.start();        System.out.println("main end");    }}

 Java  VisualVM

未启动前   

启动后:

2)、CPU占用过高

public class CPUHigh {    public static void main(String[] args) {        new Thread(new Runnable() {            @Override            public void run() {                while (true){                    System.out.println("hi");                }            }        },"thread-cpuhigh").start();    }}

    (1)、定位到占用cpu最高的进程

             top

    (2)、定位到占用cpu最高的线程

             top -H -p 进程id

    (3)、定位线程

             jstack 进程id |  grep  线程id  (16进制)  -A 30

3、Java Agent的两种实现方式自己写DEMO

       1)、

       2)、

 

参考:

 

转载地址:http://ufbnb.baihongyu.com/

你可能感兴趣的文章
看图搞懂微服务架构
查看>>
详解:java工具之解析yaml文件
查看>>
包教包会:搭建RocketMQ双主双从同步集群,
查看>>
5年Java程序员,五面蚂蚁险拿offer定级P7,大厂面试不过如此?
查看>>
大厂面试必问!HashMap 怎样解决hash冲突?
查看>>
面试屡屡碰壁,痛定思痛闭关修炼!半年后4面阿里成功拿offer
查看>>
最全的大厂最新面试249题与笔记总结:多线程+JVM +Spring+微服务+分布式+Redis+MySQL
查看>>
吊!设计模式全解:6大设计原则+23种设计模式+设计模式PK+设计模式混编
查看>>
服!看完阿里大牛手写的Java异步编程实战笔记,我惊呆了
查看>>
Java程序员跳槽,三面之后被拒,原因竟是“招不起”
查看>>
想要彻底搞懂微服务架构?必先学:SpringBoot+SpringCloud+docker
查看>>
6天面试10家,已经拿到offer,Java程序员的面试总结分享
查看>>
渣本的逆袭之路!备战3个月,三面蚂蚁金服成功斩获Offer
查看>>
10月末美团、滴滴、蘑菇街9次面试总结(Java岗)
查看>>
热气腾腾的腾讯后台开发面经(总共五面)
查看>>
深入理解设计模式(设计原则+种设计模式+设计模式PK+设计模式混编)
查看>>
谷歌大佬回国发展,吊打各大厂面试官!吐血总结大厂面试高频点及笔记解析
查看>>
面试复盘:面完字节、美团、阿里等大厂,今年面试到底问什么?
查看>>
从0到1,决战Spring Boot《Spring Boot 2实战之旅》
查看>>
5面终于拿到字节跳动offer!忍不住和大家分享一波
查看>>