JVM25-JVM性能调优实战

744 阅读4分钟

欢迎大家关注 github.com/hsfxuebao/j… ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈

1.亿级流量电商

设置的jvm参数为:

-Xms3G -Xmx3G -Xss1M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M

JVM内存具体分配:

面试题:对JVM调优,让其几乎不发生Full GC?

由于在major GC时,部分对象还是有引用存在的,所以会进入S1或S0;

对象动态年龄判断(一批对象的总大小大于S1内存大小的50%(-XX:TargetSurvivorRatio可以指定)),那么大于等于这批对象年龄的最大值的对象就可以进入老年代,老年代被占满触发Full GC;

此时需要调整jvm参数如下:设置年轻代大小为2G

-Xms3G -Xmx3G -Xmn2G -Xss1M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M

2.12306网站

12306遭遇春节大规模抢票应该如何支撑?

  • 12306应该是中国并发量最高的秒杀网站,号称并发量100W最高
  • CDN->LVS->NGINX->业务系统->每台机器1W并发  100台机器
  • 普通电商下单->下单系统->订单系统(IO)减库存->等待用户付款
  • 12306的一种可能模型:下单->减库存和订单(redis kafka)同时异步进行->等付款->减库存,最后还会把压力压到一台服务器
  • 分布式本地库存+单独服务器做库存均衡
  • 大流量的处理方法:分而治之

1.怎么得到一个事务会消耗多少内存?

  • 弄一台机器,看能承受多少TPS?是不是达到目标?扩容或调优
  • 用压测来确定

3.案例汇总

  1. 线程池运用不当产生OOM问题
  2. tomcat http-header-size设置过大导致OOM

      Java tomcat max-http-header-size配置导致的oom

   3. lambda 表达式导致方法区溢出问题(MethodArea / Perm Metaspace)

设置JVM参数:-XX:MaxMetaspaceSize=9m -XX:+PrintGCDetails

public class LambdaGC {

    public static void main(String[] args) {
        for (; ; ) {
            I i = C::n;
        }

    }
    
    public static interface I {
        void m();
    }

    public static class C {
        static void n() {
            System.out.println("hello");
        }
    }

}

运行结果:

    4.直接内存溢出问题(少见)

            《深入理解Java虚拟机》P59,使用Unsafe分配直接内存,或者使用NIO的问题

    5.栈溢出问题

          -Xss设定太小

    6.下面两段代码,哪一种是更优的写法

Object o = null;
for(int i =0; i < 100; i++){
   o = new Object();
}
// 更优

for(int i =0; i < 100; i++){
   Object o = new Object();
}
// 需要在栈上一直分配o

    7.重写finalize引发频繁GC

       小米云,HBase同步系统,系统通过nginx访问超时报警,最后排查C++程序员重写finalize引发频繁GC问题

    8.一个系统内存使用率不超过10%,但是观察GC日志,发现FGC总是频繁产生,什么引起?

          System.gc()

    9.有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G

的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G
的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了

      ① 为什么原网站慢?

         很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢

      ② 为什么会更卡顿?

          内存越大,FGC时间越长

      ③ 咋办?PS -> PN + CMS 或者 G1

四.一个案例理解常用工具    

  1. 测试代码:

    package com.mashibing.jvm.gc;
    
    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_FullGC_Problem01 {
    
        private static class CardInfo {
            BigDecimal price = new BigDecimal(0.0);
            String name = "张三";
            int age = 5;
            Date birthdate = new Date();
    
            public void m() {}
        }
    
        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 void modelFit(){
            List<CardInfo> taskList = getAllCardInfo();
            taskList.forEach(info -> {
                // do something
                executor.scheduleWithFixedDelay(() -> {
                    //do sth with info
                    info.m();
    
                }, 2, 3, TimeUnit.SECONDS);
            });
        }
    
        private static List<CardInfo> getAllCardInfo(){
            List<CardInfo> taskList = new ArrayList<>();
    
            for (int i = 0; i < 100; i++) {
                CardInfo ci = new CardInfo();
                taskList.add(ci);
            }
    
            return taskList;
        }
    }
    
    
  2. java -Xms200M -Xmx200M -XX:+PrintGC com.mashibing.jvm.gc.T15_FullGC_Problem01

  3. 一般是运维团队首先受到报警信息(CPU Memory)

  4. top命令观察到问题:内存不断增长 CPU占用率居高不下

  5. top -Hp 观察进程中的线程,哪个线程CPU和内存占比高

  6. jps定位具体java进程
    jstack 定位线程状况,重点关注:WAITING BLOCKED
    eg.
    waiting on <0x0000000088ca3310> (a java.lang.Object)
    假如有一个进程中100个线程,很多线程都在waiting on ,一定要找到是哪个线程持有这把锁
    怎么找?搜索jstack dump的信息,找 ,看哪个线程持有这把锁RUNNABLE
    作业:1:写一个死锁程序,用jstack观察 2 :写一个程序,一个线程持有锁不释放,其他线程等待

  7. 为什么阿里规范里规定,线程的名称(尤其是线程池)都要写有意义的名称
    怎么样自定义线程池里的线程名称?(自定义ThreadFactory)

  8. jinfo pid

  9. jstat -gc 动态观察gc情况 / 阅读GC日志发现频繁GC / arthas观察 / jconsole/jvisualVM/ Jprofiler(最好用)
    jstat -gc 4655 500 : 每个500个毫秒打印GC的情况
    如果面试官问你是怎么定位OOM问题的?如果你回答用图形界面(错误)
    1:已经上线的系统不用图形界面用什么?(cmdline arthas)
    2:图形界面到底用在什么地方?测试!测试的时候进行监控!(压测观察)

  10. jmap - histo 4655 | head -20,查找有多少对象产生

  11. jmap -dump:format=b,file=xxx pid :

线上系统,内存特别大,jmap执行期间会对进程产生很大影响,甚至卡顿(电商不适合)  
1:设定了参数HeapDump,OOM的时候会自动产生堆转储文件(不是很专业,因为多有监控,内存增长就会报警)  
2:<font color='red'>很多服务器备份(高可用),停掉这台服务器对其他服务器不影响</font>  
3:在线定位(一般小点儿公司用不到)

4:在测试环境中压测(产生类似内存增长问题,在堆还不是很大的时候进行转储)

12. java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError com.mashibing.jvm.gc.T15_FullGC_Problem01

  1. 使用MAT / jhat /jvisualvm 进行dump文件分析
    www.cnblogs.com/baihuitests…
    jhat -J-mx512M xxx.dump
    http://192.168.17.11:7000
    拉到最后:找到对应链接
    可以使用OQL查找特定问题对象

  2. 找到代码的问题