springboot 啟動慢分析


JVM參數設置


1. 生成GC日志並網站在線分析

  1. 生成gc日志命令
-Xloggc:./gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
  1. 在線分析網站
    https://gceasy.io/
  2. 調整過程:
    根據GC日志分析得到年輕代GC頻繁,沒有老年代GC;
    調整年輕代大小為堆的1/2,性能並沒有優化,反而有了更多消耗時間更長的GC

結論:

工程啟動慢與年輕代GC頻繁無關

2. 生成dump文件分析

  1. 生產dump文件命令
jmap -dump:format=b,file=./heap.hprof  進程號

結果:沒有發現有個別大對象占用大量內存的情況

3.分析日志

[2021-09-03 10:42:58.668] - [INFO] - [main] - [org.springframework.aop.framework.CglibAopProxy] - Unable to proxy interface-implementing method [public final java.util.List com.epoch.bdp.util.service.excel.AbstractExcelProcess.getExcelHeader(com.epoch.bdp.util.service.excel.context.ExcelProcessContext)] because it is marked as final: Consider using interface-based JDK proxies instead! 

結論:部分被代理類因為類中有final修飾的方法,無法被cglib進行代理

4.JVM啟動參數優化

這里主要涉及的啟動參數設置是下面兩個:

  1. -XX:TieredStopAtLevel=1
    使用C1編譯器,又稱為客戶端模式,相對於C2也就是服務端模式,C1編譯生成的機器碼更加關注快速啟動但是由於機器碼沒有經過編譯優化所以不適合在線上環境穩定運行。
  2. -Xverify:none/ -noverify
    通過去除字節碼的驗證來提升JVM啟動速度,同樣不適合線上對安全有要求的環境使用。
    結論:這兩種方式 都不適用於生產環境,所以並未啟用

5.springboot 懶加載方案

springboot2.2以后支持配置全局懶加載機制,springboot2.2以前實現BeanFactoryPostProcessor 類。
但是存在以下問題:

  1. 大部分對象啟動時未初始化,不好估算應用使用內存
  2. 啟動時不加載部分類,如果有錯誤不會拋出,不容易發現問題
  3. 第一次請求是時間會很慢,后續請求不會有此問題
    結論:考慮到上面的影響,以及測試過程中發現很多對象配置為懶加載會影響項目啟動,所以未采用

6.判斷類的加載時間

package com.epoch.boot.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 〈一句話功能簡述〉
 *
 * @author 劉建宇
 * @since ECS2.0
 */
@Component
public class BeanInitCostTimeBeanPostProcessor implements BeanPostProcessor {

    private static final Logger logger = LoggerFactory.getLogger(BeanInitCostTimeBeanPostProcessor.class);

    private static final ConcurrentHashMap<String, Long> START_TIME = new ConcurrentHashMap<>();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        START_TIME.put(beanName, System.currentTimeMillis());
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
     if(Objects.nonNull(START_TIME.get(beanName))){
         long costTime = System.currentTimeMillis() - START_TIME.get(beanName);
          if(costTime>300) {
              logger.error("beanName:{},cost:{}",beanName,costTime);
          }
     }
        START_TIME.clear();
        return bean;
    }
}

結論:發現有個別對象初始化時占用時間較長

7. 分析aop

注解說明

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    // true:使用cglib代理,false:使用jdk代理
    boolean proxyTargetClass() default false;
    // 控制代理的暴露方式,解決內部調用不能使用代理的場景,默認為false.
    boolean exposeProxy() default false;
}

最后判斷結果為:因為項目中配置了大量AOP切面類,嚴重影響了啟動速度


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM