系统性能优化

1. ClassNotFoundException/NoClassDefFoundError/NoSuchMethodException

       参考关于类加载的博文即可,主要关注类加载的方式,类的版本等信息

       https://www.cnblogs.com/baihuitestsoftware/articles/6382733.html

       https://www.cnblogs.com/it-worker365/p/11269635.html

2.Cpu us消耗高

linux下获取占用CPU资源最多的10个进程,可以使用如下命令组合: 或者top进入后大写的M

//加标题去标题,第三列倒序排序
ps -aux | head -1 ; ps aux | grep -v PID | sort -rn -k +3 | head
//排序
ps -aux | sort -nr -k3 | head -10

       是否是gc过于频繁,打开gc日志-Xloggc:./gc.log或者通过jstat -gcutil来查看gc和内存的情况,这种根据内存问题来处理

       下面根据top -H -p/ jstack等命令查看是否有死锁,很深的循环或递归,也可能是序列化反序列化之类对象突然变大,计算突然增加   

/**
 * Created by itworker365 on 5/17/2017.
 */
public class CpuBusyTest implements Runnable{
    public static void main (String[] args) {
        for (int a = 0; a < 1000; a++) {
            CpuBusyTest test = new CpuBusyTest();
            Thread t = new Thread(test, "t-" + a);
            t.start();
        }
    }

    @Override
    public void run() {
        long start = System.currentTimeMillis();
        long k = 0;
        for (long i = 0; i < 2000000000; i++) {
            k = 1 + i;
        }
        System.out.println(Thread.currentThread().getName() + "-----" + (System.currentTimeMillis() - start));
    }

默认TOP按照进程显示,直接输入TOP看到占用最多的进程,如下,%CPU 99.8

top -H -p ID查看该进程下的线程情况,如果有一个特别高,可以找到PID,然后转换为16进制,比如2687-》0xA7F,打印进程堆栈 jstack ID在其中找到0xA7F

我的例子并没有对应,因为中间停掉了,所以意思明白就好,这里打印出jstack信息,找到对应的线程,查看他的状态。

一个出现死锁的例子

/**
 * Created by itworker365 on 5/4/2017.
 */
public class LockTest {
    private static String A = "A";
    private static String B = "B";
    public static void main (String[] args) {
        new LockTest().deadlock();
    }
    private void deadlock () {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (A) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (B) {
                        System.out.println("AB");
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (B) {
                    synchronized (A) {
                        System.out.println("BA");
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

jstack之后显示deadlock信息

 3. 内存问题

linux下获取占用内存资源最多的10个进程,可以使用如下命令组合:或者top进入后大写的P

ps -aux | head -1 ; ps aux | grep -v PID | sort -rn -k +4 | head
ps -aux | sort -nr -k4 | head -10

    java.lang.OutOfMemoryError: Unable to create new native thread

    用命令统计出当前总java线程数ps -eLf | grep java -c, 查出当前允许的最大句柄数ulimit -u,对比看是否正确,根据需要做出对应的调整,btrace找到哪里创建的线程@OnMethod(clazz="java.lang.Thread", method="start")

    Executors.newCachedThreadPool这种来创建了一个没限制大小的线程池

    java.lang.OutOfMemoryError: Heap Size或GC overhead limit exceeded

    启动时加入-XX:+HeapDumpOnOutOfMemoryError在溢出时dump内存,之后再通过mat等工具再分析,通过btrace来定位代码

    PermGen Space 跟踪class装载情况,用traceClassLoading或者btrace,@OnMethod(clazz="java.lang.ClassLoader", method="defineClass")

    native OOM:Direct ByteBuffer(NIO)-XX:MaxDirectMemorySize=500m来实现当Direct ByteBuffer使用到500m后主动触发fgc来回收

    到底什么算频繁,如果每隔10s或更短时间就来一次cms gc或full gc才算得上

    jmap -dump:format=b,file=***log         jhat ***.log或其他工具分析

    jmap -histo打印加载的对象    jmap -histo:live来触发fgc

java.lang.OutOfMemoryError: Java heap space堆溢出,大对象多次没被回收,对比回收前后的内存使用量

StackOverflowError:递归,循环,局部变量过长,参数过多,局部变量作用域外没有释放等

java.lang.OutOfMemoryError: unable to create new native thread  操作系统没有足够的资源来创建线程,解决方法就是减少线程数量或者-Xss减小单个线程的大小

java.lang.OutOfMemoryError: PermGen space 类太多,是多个classloader或者太多反射动态加载类导致

4.文件占用大小排序

du -s -h /* | sort -nr

5. Java进程crash或退出

默认情况下jdk会生成hs_err[pid].log的文件,core dump打开的话也会生成core dump文件

-XX:+PrintGCDetails

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/log/gcdump

遇到问题分而治之,隔离问题。将问题隔离到尽可能小的领域中,比如某个特定系统、特定版本、 甚至特定机器中。之后如果是java的问题,还可以继续分析是java应用、容器、或者jdk的问题,最后应该能确定到某个模块的某些代码、一次 commit、一行配置的问题。整个排查问题的过程就是一个从上到下,一步步缩小问题范围的过程。

状态数据大致可以分为两类:

一是监控类数据,收集这类数据对于应用的性能影响很小,基本可以忽略不计,所以可以持续收集,比如GC log,应用log等;

第二类是某些瞬时数据,这些数据要么收集的代价很大,很影响系统性能,要么时效性很高,过了故障点一切可能就都不一样了,所以不能 持续收集,必须迅速的在故障出现点自动采集,比如Heap dump,core dump等。

原文地址:https://www.cnblogs.com/it-worker365/p/6867996.html