JVM实战(31)——内存溢出之请求超时

这篇具有很好参考价值的文章主要介绍了JVM实战(31)——内存溢出之请求超时。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

本章,我们将通过实际案例讲解一个Web应用的内存溢出问题,该内存溢出问题的排查涉及Tomcat的一些底层原理,最终排查发现是由于请求超时问题导致,我们先来看下系统的背景。

1.1 系统背景

生产环境的一个系统发生告警,拿到生产日志后出现如下字样:
Exception in thread "http-nio-8080-exec-1089" java.lang.OutOfMemoryError:Java heap space

很明显,Java堆内存区域发生了内存溢出异常。特别要注意的是http-nio-8080-exec-1089,由于当时系统部署在tomcat中(8080端口),所以上面这段日志的意思就是tomacat工作线程在处理请求时发生了内存溢出异常。

为什么会是tomcat的工作线程发生异常? 这就涉及tomcat的一些基本原理。

1.2 tomcat基本原理

首先,我们明确一点 Tomcat运行时本身就是一个JVM进程 ,我们写好的程序打包后放到tomcat的指定目录下,程序中的各种类会由Tomcat加载到它的JVM内存区域中,然后由tomcat来执行我们程序中的类:

JVM实战(31)——内存溢出之请求超时,jvm专题,jvm

tomcat有许多自己的工作线程,它们默认会监听8080端口。8080端口上收到的请求会均匀分配给这些工作线程,工作线程接收到请求后负责调用程序自身的Servlet进行处理。上述异常日志中的http-nio-8080-exec-1089,说白了就是上图中的tomcat工作线程,因为它负责调用Spring中的一大堆代码,发现运行时堆内存不够了,所以就抛出了异常。

Spring Boot应用可以把web容器直接内嵌在我们打包后的程序中,但本质还是一样的。

二、问题分析

知道了系统的大致情况,我们就要用MAT来分析下事故现场的堆内存快照了(线上系统记得加上JVM参数-XX:+HeapDumpOnOutOfMemoryError)。

2.1 内存快照

我们分析内存快照,首先要找到占用堆内存最大的对象。我们发现有一大堆byte[]数组占据了大约8G的内存,而当时线上机器给Tomcat的JVM堆内存也是8G。这说明,tomcat工作线程在处理请求时大量创建了这些byte[]数组,直接把堆内存占满了,从而导致内存溢出。

JVM实战(31)——内存溢出之请求超时,jvm专题,jvm

然后,我们继续分析这些byte[]数组到底是个啥,通过MAT找了很多类似下面这样的数组,每个10MB,一共约800个,总量约8G:

JVM实战(31)——内存溢出之请求超时,jvm专题,jvm

通过MAT的引用分析,发现这些数组都被一个名为org.apache.tomcat.util.threads.TaskThread的Tomcat类引用着,这个一看就是Tomcat自己的线程类。MAT可以查看当前JVM中有哪些线程存在,我们发现上述种tomcat线程一个约400个,每一个引用着2个byte[]数组。

也就是说: 400个tomcat工作线程同时在处理请求,每个线程创建了2个10MB的byte[]数组,结果就总共创建了8G的数组,进而导致了内存溢出 。

JVM实战(31)——内存溢出之请求超时,jvm专题,jvm

2.2 请求超时

根据上述分析,我们的脑海里应该有这样一副流动画面:1秒钟内来了400个请求,导致tomcat的400个工作线程同时开始处理请求,每个线程在处理请求时会创建2个10MB的byte[]数组对象,用于自用,结果瞬间把8G内存空间占满,触发内存溢出异常

但是,我们通过监控系统发现,事故现场的QPS只有100,而不是400!出现这种情况只有一种可能,请求超时了,每个请求的处理时间达到4s,这样4s内400个工作线程会在同时工作,进而导致上述问题。

JVM实战(31)——内存溢出之请求超时,jvm专题,jvm

那么现在就剩下两个问题:

  1. 每个tomcat工作线程创建的2个10MB的byte数组究竟是啥?
  2. 程序哪里出现了大量超时?

先来看第一个,tomcat的配置文件中有一个max-http-header-size:10000000配置,根据查阅tomcat文档我们知道,这个是tomcat工作线程为请求和响应创建的数组,可以适当调小些,但是10MB也在合理范围内。所以,问题的根本原因就是程序超时。

我们通过程序日志发现,有大量的Timeout Exception字样,这是程序在通过RPC调用其他系统接口时抛出的,然后通过RPC超时参数配置发现,超时时间刚好是4s!

也就是说,在某一段时间内,某个外部依赖系统刚好挂掉了,导致我们系统通过RPC调用它的接口时出现大量超时,而在超时的4s内,工作线程会hang住,从而引发内存溢出,所以 这个4s请求超时的配置是根本原因 。

JVM实战(31)——内存溢出之请求超时,jvm专题,jvm

三、系统优化

分析清楚了问题原因,优化就很简单了,直接将超时时间改为1s就可以了。这样的话,每秒100个请求过来,每个拥有2个byte数组,那总共就是2G,不会将JVM堆内存占满,然后超过1s就超时,请求结束。

超时时间的配置要根据系统运行时模型合理配置。除此之外,一些核心系统,必须要有熔断、降级、限流的机制,可以通过Hystrix来实现,没有接触过的读者可以参阅Hystrix官方资料了解。

四、总结

本章,我们通过一个实际案例分析了因为请求超时引起的内存溢出问题,以及相应的排查思路。解决这类问题的思路其实都是一致的,需要一步步去分析,在实践中积累经验,举一反三。文章来源地址https://www.toymoban.com/news/detail-823902.html

到了这里,关于JVM实战(31)——内存溢出之请求超时的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • JVM哪些区域会出现内存溢出

    JVM(Java Virtual Machine)是指Java虚拟机,是一种可以在不同平台上运行Java字节码的虚拟计算机。JVM是Java语言的核心,通过将Java代码编译成字节码并在JVM上运行,实现了跨平台的特性。 1.方法区(Metaspace) 方法区用于存储类的信息、静态变量和常量等数据。在JDK8及以上版本中

    2024年02月08日
    浏览(12)
  • JVM笔记 —— 出现内存溢出错误时时如何排查

    JVM笔记 —— 出现内存溢出错误时时如何排查

    内存溢出错误分为StackOverflowError和OutOfMemoryError,前者是栈中出现溢出,后者一般是堆或方法区出现溢出,简称OOM 1. 栈溢出 StackOverflowError 栈溢出一般都是因为没有正确的结束递归导致的,无限递归导致超出栈内存(-Xss)限制时就会抛出StackOverflowError。这种情况直接根据异常

    2024年02月13日
    浏览(9)
  • jvm 程序计算器 程序计数器是否溢出 程序计数器是做什么的 java程序计数器会内存溢出吗 程序计数器作用与用处 jvm内存模型 jvm合集(一)

    jvm 程序计算器 程序计数器是否溢出 程序计数器是做什么的 java程序计数器会内存溢出吗 程序计数器作用与用处 jvm内存模型 jvm合集(一)

    1. jvm内存模型:     内存模型:                     程序计数器                     堆                     栈                     本地方法栈                     方法区 2. java代码编译为class文件,由类加载器加载到jvm,然后

    2024年02月09日
    浏览(10)
  • jvm内存溢出排查(使用idea自带的内存泄漏分析工具)

    jvm内存溢出排查(使用idea自带的内存泄漏分析工具)

    想分析堆内存溢出,一定在运行jar包时就写上参数 -XX:+HeapDumpOnOutOfMemoryError ,可以看我之前关于如何运行jar包的文章。若你没有写。可以写上参数,重启你的项目,等你的项目发生下一次堆内存溢出异常,在运行的同级文件夹,将产生类似这样一个文件 java_pid74935.hprof ,若你

    2024年02月09日
    浏览(10)
  • 深入理解 JVM 之——Java 内存区域与溢出异常

    深入理解 JVM 之——Java 内存区域与溢出异常

    更好的阅读体验 huge{color{red}{更好的阅读体验}} 更好的阅读体验 本篇为深入理解 Java 虚拟机第二章内容,推荐在学习前先掌握基础的 Linux 操作、编译原理、计算机组成原理等计算机基础以及扎实的 C/C++ 功底。 该系列的 GitHub 仓库:https://github.com/Doge2077/learn-jvm Java 虚拟机在

    2024年02月09日
    浏览(13)
  • JVM-内存溢出的原因、CPU占满的原因

    OOM的排查思路_oom排查_java排坑日记的博客-CSDN博客 每个进程的内存(限制,譬如2G)=最大堆容量+最大方法区容量+程序计数器+虚拟机栈和本地方法栈。多线程下每个线程栈越大,越容易OOM.                 1)大对象(从数据库里一次请求了大量的数据)         

    2024年02月10日
    浏览(14)
  • JVM:全面理解线上服务器内存溢出(OOM)问题处理方案(一)

    JVM:全面理解线上服务器内存溢出(OOM)问题处理方案(一)

    前段时间生产上遇到了OOM问题,导致服务出现了短时间的不可用,还好处理及时,否则也将酿成大祸。OOM问题也是生产中比较重要的问题,所以本期我们针对OOM问题特别讲解,结合理论与实际案例来带大家彻底攻克OOM问题处理。 要解决问题,我们首先要清楚问题产生的原因。

    2024年02月12日
    浏览(12)
  • java面经03-虚拟机篇-jvm内存结构&垃圾回收、内存溢出&类加载、引用&悲观锁&HashTable、引用&finalize

    java面经03-虚拟机篇-jvm内存结构&垃圾回收、内存溢出&类加载、引用&悲观锁&HashTable、引用&finalize

    要求 掌握 JVM 内存结构划分 尤其要知道方法区、永久代、元空间的关系 结合一段 java 代码的执行理解内存划分 执行 javac 命令编译源代码为字节码 执行 java 命令 创建 JVM,调用类加载子系统加载 class,将类的信息存入 方法区 创建 main 线程,使用的内存区域是 JVM 虚拟机栈 ,

    2024年02月09日
    浏览(15)
  • JVM实战(23)——内存碎片优化

    JVM实战(23)——内存碎片优化

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月18日
    浏览(41)
  • JVM工作原理与实战(二十一):内存管理

    JVM工作原理与实战(二十一):内存管理

    JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、不同语言的内存管理 1.C/C++的内存管理 2.Java的内存管理 二、垃圾回收的对比 1.自动垃圾回收与手动垃圾回收的对比 2.优点与缺点 总结 JVM作为Java程序的运行环境,其负责解释和执行字节码,管理

    2024年01月21日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包