1 背景

最近工作中碰到一个生产问题,就是应用服务在使用 OkHttpClient 时,在创建大量对外连接时线程堆积导致内存溢出。

主要表现是在流量极低的情况下,即平均 qps 在 1~4 左右的情况下,各主要线程都很低,但是系统活跃线程却很高,超过了限制的阈值,如果持续下去,线程堆积过高则会导致应用程序直接挂掉。

2 排查

​2.1 原因

在对应用服务的其中一个 pod 的线程栈 dump 出来分析后,发现 dump 出来的文件中,有 266 个线程,其中 145 个都来自于同一个ConnectionPool(OkHttp ConnectionPool),而且是在流量不高的情况下。

经分析主要原因是应用中在创建 OkHttpClient 对象时,没有创建同一个 OkHttpClient 实例并重复使用,而是对于所有的 http 请求都重复创建一个新的实例,而每个实例都有自己的连接池和线程池,从而导致线程大量堆积。

而 OkHttpClient 默认的最大线程空闲数是 5,keepAlive 时间为 5 分钟,也就是发起一次网络连接后,5 分钟内不会断开连接,从而导致在创建大量对外连接时内存溢出。

而查看 OkHttpClient 类的源码发现,通过 OkHttp 创建每个OkHttpClient 实例的时候,每个客户端都会持有自己的连接池和线程池。

对于通过 OkHttp 创建的所有的 http 请求,在创建一个 OkHttpClient 实例并重复使用时,重用它的连接池和线程池可以减少延迟和节省内存。

2.2 验证过程

2.2.1 修改前

查看应用程序中的代码可以看到,在创建 OkHttpClient 实例的时候,并没有创建一个可复用的实例,而是每次创建 http 请求时,都会 new 一个新的 OkHttpClient 实例。

在 jmeter 模拟多个线程同时请求应用服务的接口,每次请求 300 个线程,通过多次请求之后,通过 jconsole 工具可以很清楚的看到线程数刚开始的时候基本为 0,但多次模拟请求过后很快就超过了 3000 个,然后电脑连续挂了 2 次。。。

并且从下图中,我们可以非常明显地看到,这些线程大部分都是 OkHttp ConnectionPool。

2.2.2 修改后

修改之后,创建一个共享的 OkHttpClient 对象,jmeter 每次模拟 300 请求,通过 jconsole 可以观察到,发现第一次模拟达到了一个峰值后,后面无论再怎么模拟,峰值基本都不再改变了。

而修改之前每次模拟 300 请求,模拟几次之后会发现线程数一直在蹭蹭往上涨,直至线程大量堆积导致应用程序崩溃。

3 解决

创建一个共享的 OkHttpClient 对象即可,而不是每次调用方法都单独创建一个 OkHttpClient 对象,每个 OkHttpClient 对象都有自己的连接池和线程池,会导致大量的线程堆积,从而可能会导致程序崩溃。

开两个服务内存溢出_应用服务OkHttpClient创建大量对外连接时内存溢出相关推荐

  1. java 二维数组内存溢出_程序员:学习心得,Java内存区域,内存溢出异常

    Java 内存区域 Heap 线程公有 存放实例对象 是GC主要管理区域,因此可以更细致的划分为:新生代.老年代 再细致一点划分:Eden区.From Survivor区.To Survivor区 内 ...

  2. jvm 内存镜像_镜像镜像–使用反射在运行时查看JVM内部

    jvm 内存镜像 开发人员:Takipi会告诉您何时新代码在生产中中断– 了解更多 我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射. 它是Java和Scala编程的主要方面,它使我们 ...

  3. mysql 数据库大小与内存关系_【MYSQL】CPU资源和可用内存大小对数据库性能的影响...

    前言 可能影响到数据库性能的几个点,其一就是服务器硬件,也是本节要说的CPU与可用内存. 引入 当热数据超过可用内存大小,MemCache存储引擎缓存层容易失效(当缓存大量失效时,容易产生大量的网络传 ...

  4. java 堆外内存 查看_超干货!Cassandra Java堆外内存排查经历全记录

    背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...

  5. java 测试内存溢出_浅析软件测试人员如何对JVM进行内存溢出检测

    一.什么是JVM,检测JVM的意义 JVM是java virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各 ...

  6. php mysql 内存溢出_关于MySQL的整型数据的内存溢出问题的应对方法_MySQL

    今天接到一个朋友电话说是觉的数据库被别人更改了,出现数据不对的问题 .经过很久的排查是数据类型溢出了(发生问题的版本是MySQL 5.1).后来通过给朋友那边把MySQL 5.1升级到MySQL 5. ...

  7. java缓存内存泄漏_记一次mybaits缓存导致的内存溢出 java.lang.OutOfMemoryError: Java heap space...

    先贴一下错误截图 org.springframework.web.util.NestedServletException: Handler dispatch failed; nested except ...

  8. java 内存测试_请你说一下java jvm的内存机制

    Java虚拟机栈是线程私有的,它的生命周期与线程相同. 局部变量表存放了编译时期可知的各种基本数据类型和对象引用.局部变量表所需的内存空间在编译时期完成分配,当进入一个方法时,这个方法需要在栈帧中分配 ...

  9. 写一段代码提高内存占用_记录一次生产环境中Redis内存增长异常排查全流程!...

    点击上方 IT牧场 ,选择 置顶或者星标 技术干货每日送达 最近 DBA 反馈线上的一个 Redis 资源已经超过了预先设计时的容量,并且已经进行了两次扩容,内存增长还在持续中,希望业务方排查一下容量 ...

最新文章

  1. javaaop模式供其他项目调用_Java 分布式架构的 开源的支付项目 调试实战
  2. java es 数据批量导入_ElasticSearch—Java批量导入导出
  3. webx学习(二)——Webx Framework
  4. 头脑仅仅是一个实验室
  5. .jar文件参与android源码编译
  6. uniapp uView u-picker组件三级联动Demo
  7. 580刷590bios_RX580 2048sp刷vbios降为RX570 用上黑苹果美滋滋
  8. class uesrfun.php,帝国cms教程:列表页面批量添加Tags -电脑资料
  9. java手机号中间4位使用*替换
  10. win8计算机关机时 重新配置windows 以后打印机不能用了,win8系统打印机发送打印任务后不打印自动消失的技巧介绍...
  11. Rocchio算法( pronounced Rockey-O)二分类
  12. Html5 Egret游戏开发 成语大挑战(一)开篇
  13. 应用统计学与R语言实现学习笔记(十二)——主成分分析
  14. border-radius和border-image
  15. 像李欣频一样思考人生~
  16. 网络教育计算机 判断,重庆网络教育计算机应用基础练习题(3)
  17. clickhouse副本和分片
  18. 刨根问底 Kafka,面试过程真好使
  19. HCIP(华为高级网络安全工程师)(第五天)(OSPF协议1)
  20. Glove模型训练自己的中文数据集词向量详细步骤

热门文章

  1. html获取随机字母,JavaScript实现4位随机验证码的生成
  2. java 序列化 写入mysql_java 序列化到mysql数据库中
  3. mysql 事件计划_mysql 事件计划
  4. linux中c语言延时毫秒函数,linux下写个C语言程序,要求有0.5微秒以下的延时,要怎样写...
  5. Java 算法 陶陶摘苹果2
  6. python 自动收集经济数据_完结】数据分析思维案例实战92 用Python自动办公,做职场高手【更新中】91.一课经济...
  7. Linux/Ubuntu 单机安装配置 zookeeper
  8. 解决xlwt保存的xlsx文件无法打开的问题
  9. 计算机编译原理 张,计算机编译原理概念总结
  10. ActiveMQ消息队列的使用