如果你的spring-boot应用里tomcat线程耗cpu较高,并主要耗在做读取jar的操作上(堆栈类似下面),可能跟我们遇到同样的问题。

  1. CRC32.update(byte[], int, int) line: 76
  2. JarInputStream(ZipInputStream).read(byte[], int, int) line: 200
  3. JarInputStream.read(byte[], int, int) line: 207
  4. JarInputStream(ZipInputStream).closeEntry() line: 140
  5. JarInputStream(ZipInputStream).getNextEntry() line: 118
  6. JarInputStream.getNextEntry() line: 142
  7. JarInputStream.getNextJarEntry() line: 179
  8. JarWarResourceSet.getArchiveEntries(boolean) line: 112
  9. JarWarResourceSet(AbstractArchiveResourceSet).getResource(String) line: 256
  10. StandardRoot.getResourceInternal(String, boolean) line: 280
  11. CachedResource.validateResource(boolean) line: 95
  12. Cache.getResource(String, boolean) line: 69
  13. StandardRoot.getResource(String, boolean, boolean) line: 215
  14. StandardRoot.getResource(String) line: 205
  15. Mapper.internalMapWrapper(Mapper$ContextVersion, CharChunk, MappingData) line: 1027
  16. Mapper.internalMap(CharChunk, CharChunk, String, MappingData) line: 842
  17. Mapper.map(MessageBytes, MessageBytes, String, MappingData) line: 698
  18. CoyoteAdapter.postParseRequest(Request, Request, Response, Response) line: 672
  19. CoyoteAdapter.service(Request, Response) line: 344
  20. Http11Processor.service(SocketWrapperBase<?>) line: 784
  21. Http11Processor(AbstractProcessorLight).process(SocketWrapperBase<?>, SocketEvent) line: 66
  22. AbstractProtocol$ConnectionHandler<S>.process(SocketWrapperBase<S>, SocketEvent) line: 802
  23. NioEndpoint$SocketProcessor.doRun() line: 1410
  24. NioEndpoint$SocketProcessor(SocketProcessorBase<S>).run() line: 49
  25. ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 1142
  26. ThreadPoolExecutor$Worker.run() line: 617
  27. TaskThread$WrappingRunnable.run() line: 61
  28. TaskThread(Thread).run() line: 745

这种情况只发生在 spring-boot 1.4.x版本(及1.3.x版本,更早的没有确认),1.5.x已经没有这个问题。

主要的改变在org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory的内部类StoreMergedWebXmlListeneronStart方法:

  1. // TomcatEmbeddedContext 启动时触发了该监听器
  2. private void onStart(Context context) {
  3. ServletContext servletContext = context.getServletContext();
  4. if (servletContext.getAttribute(MERGED_WEB_XML) == null) {
  5. servletContext.setAttribute(MERGED_WEB_XML, getEmptyWebXml());
  6. }
  7. // 注意最后这句,1.5.3版本已经去掉了这句,它导致变慢
  8. TomcatResources.get(context).addClasspathResources();
  9. }

addClasspathResources方法里对于jar资源的处理,不同的tomcat版本方式有所不同,spring-boot 中如果使用嵌入式的 tomcat8 的话这些jar资源会记录到StandardRoot里的jarResources集合里,它们会被定时清理。

tomcat容器的后台线程(ContainerBackgroundProcessor)会触发StandardRoot里的清理逻辑

  1. public void backgroundProcess() {
  2. cache.backgroundProcess();
  3. gc();
  4. }
  5. public void gc() {
  6. for (List<WebResourceSet> list : allResources) {
  7. for (WebResourceSet webResourceSet : list) {
  8. webResourceSet.gc();
  9. }
  10. }
  11. }
  12. // JarWarResourceSet里的gc方法
  13. public void gc() {
  14. synchronized (archiveLock) {
  15. if (archive != null && archiveUseCount == 0) {
  16. try {
  17. archive.close();
  18. } catch (IOException e) {
  19. // Log at least WARN
  20. }
  21. archive = null;
  22. archiveEntries = null;
  23. }
  24. }
  25. }

请求过来时,Mapper阶段会根据请求路径去找映射的资源,Cache不管命中还是未命中,都会对资源进行validate,在validateResource时要去遍历WebResourceRoot里所有的资源(包括所有的jar资源),若应用依赖的jar比较多时,会导致cpu较高。

spring-boot 1.5 版本里不会再将 BOOT-INF/lib 下的所有jar添加到tomcat的WebResourceRoot里,升级到1.5.3后这个情况没有再发生。

http://hongjiang.info/spring-boot-1-4-bug/

spring-boot 1.4.x遇到的cpu高的问题的更多相关文章

  1. Spring boot 1.3.5 RELEASE 官方文档中文翻译--Part2:新手入门

    Part II. 新手入门 如果你刚刚开始学习Spring boot或"普通"的Spring,这部分非常适合你!在这里,我们回答了最基础的"什么是?".&quo ...

  2. spring boot 1.x完整学习指南(含各种常见问题servlet、web.xml、maven打包,spring mvc差别及解决方法)

    spring boot 入门 关于版本的选择,spring boot 2.0开始依赖于 Spring Framework 5.1.0,而spring 5.x和之前的版本差距比较大,而且应该来说还没有广 ...

  3. 【转】Spring Boot干货系列:(一)优雅的入门篇

    转自Spring Boot干货系列:(一)优雅的入门篇 前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社区中热度一直很高,所以决定花时间来了解和学习,为自己做 ...

  4. Spring Boot干货系列:(一)优雅的入门篇

    Spring Boot干货系列:(一)优雅的入门篇 2017-02-26 嘟嘟MD 嘟爷java超神学堂   前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社 ...

  5. 《Spring Boot官方指南》(二)入门

    如果您刚开始接触Spring Boot,或者简称’Spring’, 这个部分对您来说非常有用.这个部分提供了“是什么?”,“怎么做?”和 “为什么?”的解释.您除了会阅读一份附带Spring Boot ...

  6. Spring boot参考指南

    介绍 转载自:https://www.gitbook.com/book/qbgbook/spring-boot-reference-guide-zh/details 带目录浏览地址:http://ww ...

  7. 【spring boot】SpringBoot初学(1) - Hello World

    前言 此文只是记录自己简单学习spring boot的笔记.所以,文章很多只是初步理解,可能存在严重错误. 一.Spring boot的初步理解 1.spring boot的目标 (摘自:spring ...

  8. Spring Boot从入门到精通(八)日志管理实现和配置信息分析

    Spring Boot对日志的处理,与平时我们处理日志的方式完全一致,它为Java Util Logging.Log4J2和Logback提供了默认配置.对于每种日志都预先配置使用控制台输出和可选的文 ...

  9. spring boot springMVC扩展配置 。WebMvcConfigurer ,WebMvcConfigurerAdapter

    摘要: 在spring boot中 MVC这部分也有默认自动配置,也就是说我们不用做任何配置,那么也是OK的,这个配置类就是 WebMvcAutoConfiguration,但是也时候我们想设置自己的 ...

  10. 是时候为Spring Boot 3.0做准备了

    2018年2月28日Spring Boot进入2.0时代,距今已经超过4年了. 2022 年 11 月 Spring Boot 3.0 将正式发布,它将基于 Spring Framework 6.0, ...

随机推荐

  1. WebStrom-JS编程小技巧

    快速打印某个名为***的对象:***.log回车效果如下:

  2. 类的互相包含------新标准c++程序设计

    #include<iostream> using namespace std; class A; class B{ public: void f(A* pt){}; } class A{ ...

  3. c++内存模型------计算机系统核心概念及软硬件实现

    c++编程语言有3中不同类项的变量:全局变量.局部变量和动态分配变量.变量的值存储在计算机的内存中,但是变量存储的方式取决于变量的类项.3种类型的变量分别对应存储器中3个特定的区域: 全局变量存放在存 ...

  4. 在Linux环境下的卸载Oracle11G操作

    1.使用SQL*PLUS停止数据库[oracle@OracleTest oracle]$ sqlplus /nolog SQL> connect / as sysdba SQL> shut ...

  5. spring boot 第一个Dome

    1.创建Maven项目 按照下面的步骤 项目创建完成后的目录结构 2. 参照Spring boot官方文档修改pom.xml 修改 maven编译的jdk版本 将spring boot设置为 pare ...

  6. Java面向对象之接口interface 入门实例

    一.基础概念 (一)接口可以简单的理解为,是一个特殊的抽象类,该抽象类中的方法都是抽象的. 接口中的成员有两种:1.全局常量 2.抽象方法 定义接口用关键字interface,接口中的成员都用固定的修 ...

  7. Python3之configparser模块

    1. 简介 configparser用于配置文件解析,可以解析特定格式的配置文件,多数此类配置文件名格式为XXX.ini,例如mysql的配置文件.在python3.X中 模块名为configpars ...

  8. express + vue 项目搭建

    最近建了一个node服务端加vue前端的项目 安装node :npm install node 安装express :npm install express -g (-g全局安装) 构建express ...

  9. Centos文章列表

    1.Linux 中将用户添加到组的指令:https://cnzhx.net/blog/linux-add-user-to-group/ 2.CentOS7为firewalld添加开放端口及相关操作:h ...

  10. Servlet记录

    [Servlet]java语言编写动态资源的开发技术,普通的java类 [转发与重定向的区别] 转发在服务器端完成的:重定向是在客户端完成的 转发的速度快:重定向速度慢 转发的是同一次请求:重定向是两 ...