springboot 启动慢分析
JVM参数设置
1. 生成GC日志并网站在线分析
- 生成gc日志命令
-Xloggc:./gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
- 在线分析网站
https://gceasy.io/ - 调整过程:
根据GC日志分析得到年轻代GC频繁,没有老年代GC;
调整年轻代大小为堆的1/2,性能并没有优化,反而有了更多消耗时间更长的GC
结论:
工程启动慢与年轻代GC频繁无关
2. 生成dump文件分析
- 生产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启动参数优化
这里主要涉及的启动参数设置是下面两个:
- -XX:TieredStopAtLevel=1
使用C1编译器,又称为客户端模式,相对于C2也就是服务端模式,C1编译生成的机器码更加关注快速启动但是由于机器码没有经过编译优化所以不适合在线上环境稳定运行。 - -Xverify:none/ -noverify
通过去除字节码的验证来提升JVM启动速度,同样不适合线上对安全有要求的环境使用。
结论:这两种方式 都不适用于生产环境,所以并未启用
5.springboot 懒加载方案
springboot2.2以后支持配置全局懒加载机制,springboot2.2以前实现BeanFactoryPostProcessor 类。
但是存在以下问题:
- 大部分对象启动时未初始化,不好估算应用使用内存
- 启动时不加载部分类,如果有错误不会抛出,不容易发现问题
- 第一次请求是时间会很慢,后续请求不会有此问题
结论:考虑到上面的影响,以及测试过程中发现很多对象配置为懒加载会影响项目启动,所以未采用
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切面类,严重影响了启动速度
springboot 启动慢分析的更多相关文章
- SpringBoot启动原理分析
用了差不多两年的SpringBoot了,可以说对SpringBoot已经很熟了,但是仔细一想SpringBoot的启动流程,还是让自己有点懵逼,不得不说是自己工作和学习的失误,所以以此文对Spring ...
- SpringBoot启动流程分析(五):SpringBoot自动装配原理实现
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(六):IoC容器依赖注入
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(一):SpringApplication类初始化过程
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(二):SpringApplication的run方法
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析(四):IoC容器的初始化过程
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- SpringBoot启动流程分析原理(一)
我们都知道SpringBoot自问世以来,一直有一个响亮的口号"约定优于配置",其实一种按约定编程的软件设计范式,目的在于减少软件开发人员在工作中的各种繁琐的配置,我们都知道传统的 ...
- SpringBoot启动流程分析
前景提示 @ComponentScan 的处理都放在org.springframework.context.annotation.ConfigurationClassParser#doProcess ...
- SpringBoot源码学习3——SpringBoot启动流程
系列文章目录和关于我 一丶前言 在 <SpringBoot源码学习1--SpringBoot自动装配源码解析+Spring如何处理配置类的>中我们学习了SpringBoot自动装配如何实现 ...
随机推荐
- 【Docker】10 容器存储
将容器保存为一个镜像: docker commit 容器的名称 创建的镜像的名称 将镜像保存为一个tar包文件: docker save -o tar包文件名称.tar 镜像名称 可以看到Docker ...
- 如何为anaconda配置动态链接库——ERROR: compiler_compat/ld: cannot find
现在为python编译lib库的环境主要是使用anaconda,而之前往往都是使用自编译python环境,然后使用Linux的系统lib环境,但是现在由于都是使用anaconda环境来编译python ...
- 从hp的暗影精灵4来看移动cpu的实际性能表现与官方出厂性能数据之间的差距
手上有一款暗影精灵4的笔记本,CPU为i7-9750H,官方给出的睿频为4.5Ghz,但是自己使用过程中最高睿频只能达到3.9Ghz与4.1Ghz之间,根本就没有超过4.1Ghz的时候. (图的原网址 ...
- mysql数据库主从同步读写分离(二)读写分离实现
步骤: a.解压文件 b.添加如下配置文件 c.mysql-proxy.conf配置内容如下: 1 [mysql-proxy] 2 admin-username=proxy 3 admin-passw ...
- 如何对MIL-STD-1553B进行选型
MIL-STD-1553B产品选型是一个复杂而细致的过程,需要综合考虑多个因素以确保所选产品能够满足特定应用场景的需求. 一.引言 MIL-STD-1553B作为一种广泛应用于航空航天领域的数据总 ...
- udp协议实现组播功能
/*************************************************************************************************** ...
- 高性能无锁队列 Disruptor 核心原理分析及其在i主题业务中的应用
作者:来自 vivo 互联网服务器团队- Li Wanghong 本文首先介绍了 Disruptor 高性能内存队列的基本概念.使用 Demo.高性能原理及源码分析,最后通过两个例子介绍了 Disru ...
- 15. 从0开始学ARM-位置无关码
@ 目录 十九.位置无关码 一.为什么需要位置无关码? 1. exynos 4412启动流程 二.怎么实现位置无关码? 1. 什么是<编译地址>?什么是<运行地址>? 2. 举 ...
- C#模拟键盘输入、键状态和监听键盘消息
模拟键盘输入 模拟键盘输入的功能需要依赖Windows函数实现,这个函数是SendInput,它是专门用来模拟键盘.鼠标等设备输入的函数. 另外和键盘输入相关的函数还有SendKeys,它是Syste ...
- WPF使用Grid布局
WPF布局 WPF布局基础 布局原则 一个窗口中只能包含一个元素 不应显示设置元素尺寸 不应使用坐标设置元素的位置 可以嵌套布局容器 布局容器 StackPanel: 水平或垂直排列元素.Orient ...