Java详解线上内存暴涨问题定位和解决方案

前因:

因为REST规范,定义资源获取接口使用GET请求,参数拼接在url上。

如果按上述定义,当参数过长,超过tomcat默认配置 max-http-header-size :8kb

会报一下错误信息:

Request header is too large

可以修改springboot配置,调整请求头大小

server:
    max-http-header-size: xxx  

后果:

如果max-http-header-size设置过大,会导致接口吞吐下降,jvm oom,内存泄漏。

因为tomcat 会用HeapByteBuffer 预分配请求头内存大小,在堆上分配。

请求和响应都是一样的配置,每次请求处理预先分配,2倍配置值内存大小在 jvm 堆中

请求过多,导致线上内存暴涨,老年代有3GB多。使用jmap dump线上内存数据,使用 JProfiler 分析。

符合配置大小和源码对象

数组有3GB,和老年代和eden区总和大小相近。

-XX:PretenureSizeThreshold jvm参数用来设置默认值,当数组或对象大小超过这个设定值,直接在 Old Gen 老年代分配;默认值0,当超过eden区的大小的时候,直接分配到old区。

使用 java -XX:+PrintCommandLineFlags -version

发现并没有使用
-XX:PretenureSizeThreshold参数,所以是

max-http-header-size设置过大,eden区分配不够,直接分配到old区,堆区内存不够,自动扩容,导致old区数据越来越多,频繁触发FullGC。

JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小 于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、 -Xmx相等以避免在每次GC后调整堆的大小。

其中http-nio-9005-exec-线程有146个,和前面配置需要分配的20M内存请求,相乘的数据与3000MB相近。

tomcat任务线程池 最大线程数200,存活时间60s

因为TaskQueue 重写了offer方法,在线程池大小小于最大线程数时,任务不会放入任务队列,只会交给现有线程执行;存活时间60s,只有当线程空闲60s才会被回收,也就是**60秒内请求要小于当前线程数,**才会有空闲线程。这就导致了线程不能及时被回收。请求数下降,但是内存还是居高不下。

解决方案:

max-http-header-size修改为默认值,接口请求方式修改为POST,请求参数放置于body

到此这篇关于Java详解线上内存暴涨问题定位和解决方案的文章就介绍到这了,更多相关Java 内存暴涨内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • windows java.exe内存暴涨解决、idea跑java\ tomcat内存无限增长

    最近突然遇到个问题:用 idea 跑 Tomcat 服务,不到30分钟 内存就吃完了.用任务管理器查看,发现 java.exe占了10G内存!! 查了各种方法 一. idea Tomcat 配置 没用!!! 二.idea idea64.exe.vmoptions 安装目录下的 bin 下的 idea64.exe.vmoptions 配置,还是 C:\Users\Administrator\.IntelliJIdea2019.1\config 下的 idea64.exe.vmoptions 配置

  • Java详解线上内存暴涨问题定位和解决方案

    前因: 因为REST规范,定义资源获取接口使用GET请求,参数拼接在url上. 如果按上述定义,当参数过长,超过tomcat默认配置 max-http-header-size :8kb 会报一下错误信息: Request header is too large 可以修改springboot配置,调整请求头大小 server: max-http-header-size: xxx 后果: 如果max-http-header-size设置过大,会导致接口吞吐下降,jvm oom,内存泄漏. 因为tom

  • java排查一个线上死循环cpu暴涨的过程分析

    问题,打一个页面cpu暴涨,打开一次就涨100%,一会系统就卡的不行了. 排查方法,因为是线上的linux,没有用jvm监控工具rim链接上去. 只好用命令排查: top cpu排序,一个java进程cpu到500%了,什么鬼..... 查到对应java进程 jps || ps -aux | grep 端口 pid=13455 查看进程中线程使用情况 T排序 查看cpu占用time最高的线程编号 top -Hp 13455 有个线程9877 的时间一直在爆涨 获取线程十六进制地址9877 (十六

  • Java 详解包装类Integer与int有哪些共通和不同

    目录 1.包装类型是什么? 2.基本类型和包装类型有什么区别? 3.解释一下自动装箱和自动拆箱? 4.int 和 Integer 有什么区别? 5.两个new生成的Integer变量的对比 6.Integer变量和int变量的对比 7.非new生成的Integer变量和new Integer()生成变量的对比 8.两个非new生成的Integer对象的对比 1.包装类型是什么? Java 为每一个基本数据类型都引入了对应的包装类型,int 的包装类就是 Integer,从 Java 5 开始引入

  • Java详解数据类型的定义与使用

    目录 标识符和关键字 标识符 什么是标识符 标识符的定义规则 关键字 常量和变量 常量 变量 变量的声明格式 变量的声明 基本数据类型 整数类型 浮点类型 浮点类型常量 浮点类型变量 字符类型 字符型 字符串型 布尔类型 基本数据类型的转换 自动类型转换 强制类型转换 标识符和关键字 标识符 读音 biao zhi fu 什么是标识符 包.类.变量.方法…等等,只要是起名的地方,那个名字就是标识符 标识符的定义规则 四个可以:可以是数字.字母.下划线(_).美元符号($),我们一般起名尽量使用英

  • Java详解实现多线程的四种方式总结

    目录 前言 一.四种方式实现多线程 1.继承Thread类创建线程 2.实现Runnable接口创建线程 3.实现Callable接口 4.实现有返回结果的线程 二.多线程相关知识 1.Runnable 和 Callable 的区别 2.如何启动一个新线程.调用 start 和 run 方法的区别 3.线程相关的基本方法 4.wait()和 sleep()的区别 5.多线程原理 前言 Java多线程实现方式主要有四种: ① 继承Thread类.实现Runnable接口 ② 实现Callable接

  • 详解LeakCanary分析内存泄露如何实现

    目录 前言 LeakCanary的使用 LeakCanary原理 源码浅析 初始化 使用 总结 前言 平时我们都有用到LeakCanary来分析内存泄露的情况,这里可以来看看LeakCanary是如何实现的,它的内部又有哪些比较有意思的操作. LeakCanary的使用 官方文档:square.github.io/leakcanary/… 引用方式 dependencies { // debugImplementation because LeakCanary should only run i

  • java 详解类加载器的双亲委派及打破双亲委派

    java 详解类加载器的双亲委派及打破双亲委派 一般的场景中使用Java默认的类加载器即可,但有时为了达到某种目的又不得不实现自己的类加载器,例如为了达到类库的互相隔离,例如为了达到热部署重加载功能.这时就需要自己定义类加载器,每个类加载器加载各自的类库资源,以此达到资源隔离效果.在对资源的加载上可以沿用双亲委派机制,也可以打破双亲委派机制. 一.沿用双亲委派机制自定义类加载器很简单,只需继承ClassLoader类并重写findClass方法即可.如下例子: ①先定义一个待加载的类Test,它

  • Java 详解单向加密--MD5、SHA和HMAC及简单实现实例

    Java 详解单向加密--MD5.SHA和HMAC及简单实现实例 概要: MD5.SHA.HMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法. MD5 MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致.MD5是输入不定长度信息,输出固定长度128-bits的算法. MD5算法具有以下特点: 1.压缩性:任意长度的数据,算出的MD5值长度都是固定的. 2.容易计算:从原数据计算出MD5值很容易. 3.抗修改性:对原数据进行任何

  • 详解Swift的内存管理

    内存管理 和OC一样, 在Swift中也是采用基于引用计数的ARC内存管理方案(针对堆空间的内存管理) 在Swift的ARC中有三种引用 强引用(strong reference):默认情况下,代码中涉及到的引用都是强引用 弱引用(weak reference):通过weak定义弱引用 无主引用(unowned reference):通过unowned定义无主引用 weak 弱引用(weak reference):通过weak定义弱引用必须是可选类型的var,因为实例销毁后,ARC会自动将弱引用

  • 详解C/C++内存区域划分(简而易懂)

    C语言在内存中一共分为如下几个区域,分别是: 1. 内存栈区: 存放局部变量名: 2. 内存堆区: 存放new或者malloc出来的对象: 3. 常数区: 存放局部变量或者全局变量的值: 4. 静态区: 用于存放全局变量或者静态变量: 5. 代码区:二进制代码. 知道如上一些内存分配机制,有助于我们理解指针的概念. C/C++不提供垃圾回收机制,因此需要对堆中的数据进行及时销毁,防止内存泄漏,使用free和delete销毁new和malloc申请的堆内存,而栈内存是动态释放. C/C++内存区域

随机推荐