记一次OutOfMemory定位过程
背景
最近有个项目部署到了AWS,部署方案是ECS+Docker+Java
Launch type | CPU Units | Memory |
---|---|---|
FARGATE | 1024 | 4G |
运行后发现程序表现不符合预期——每当任务繁忙时大量的task会被关闭并启动新的task,关闭原因都是OutOfMemory,甚至连2个线程的并发能力都没有。
Details
---
Status reason | OutOfMemoryError: Container killed due to memory usage
Exit Code | 137
Timeline
找了几个典型的case,首先在AWS上轻而易举地复现此问题,然后把数据移植到本地测试,从jvisualvm中观察JVM heap size却一直十分平稳,没有出现OutOfMemory。由于应用主要承担计算任务并有大量的IO操作,故花了几天时间研究怎么减少IO读写,却一无所获,直到昨天意外发现有段代码输出不符合预期
private static final int MB_UNIT = 1024 * 1024;
public void scheduleTask() {
try {
long freeMemory = Runtime.getRuntime().freeMemory();
LOGGER.info("start batchCalculation usedMemory={}MB freeMemory={}MB", (Runtime.getRuntime().totalMemory() - freeMemory) / MB_UNIT, freeMemory / MB_UNIT);
...
freeMemory = Runtime.getRuntime().freeMemory();
LOGGER.info("finish batchCalculation usedMemory={}MB maxMemory={}MB freeMemory={}MB", (Runtime.getRuntime().totalMemory() - freeMemory) / MB_UNIT, Runtime.getRuntime().maxMemory() / MB_UNIT, freeMemory / MB_UNIT);
} finally {
MDC.clear();
}
}
在AWS跑出的结果
2018-05-30 09:45:00,000 INFO class=c.m.schedule.ScheduledTasks thread=scheduled-task-pool-1 request_id="24da9c0c-e3e5-451f-8b5d-0898c68252cc" service_name=api event_description="start batchCalculation usedMemory=905MB freeMemory=1982MB"
2018-05-30 09:45:10,016 INFO class=c.m.schedule.ScheduledTasks thread=scheduled-task-pool-1 request_id="24da9c0c-e3e5-451f-8b5d-0898c68252cc" service_name=api event_description="finish batchCalculation usedMemory=905MB maxMemory=6651MB freeMemory=1982MB"
其中maxMemory=6651MB明显超过4G。应用使用的JVM参数如下:
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1
若上述参数生效,JVM的heap size为容器最大的可用内存(即~4G)。那么可能是JDK版本的问题,为了验证猜想,推送了一个新的image到ECS并运行
ENTRYPOINT exec java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XshowSettings:vm -version
得到结果如下:
VM settings:
Max. Heap Size (Estimated): 6.50G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-1~deb9u1-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)
从上面的结果可知JDK版本(>1.8.0_131)并没有问题。既然JDK版本没有问题,JVM Heap size却不符合预期,那么问题应该是ECS或JVM配置,JVM在扩容时以机器的可用内存(6G)为上限,然而ECS已设置task的内存上限为4G,当任务繁忙时,应用尝试申请超过4G的内存,触发了ECS的内存上限条件导致被关闭。于是尝试使用Xmx/Xms参数限制JVM heap size,修改启动命令并重新推送image和部署
ENTRYPOINT exec java -Xmx3072m -Xms3072m -XshowSettings:vm -jar app.jar
启动后看到VM设置:
VM settings:
Min. Heap Size: 3.00G
Max. Heap Size: 3.00G
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
开启4个线程并发运行20分钟后一切如常,没有OutOfMemory。对比之下,显然是因为-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1
没生效。于是再次加入-XX:+PrintGCDetails -XX:+PrintGCDateStamps
看看gc详情
ENTRYPOINT exec java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XshowSettings:vm -jar app.jar
使用上述配置重新部署,在task因OutOfMemory被关闭后根据GC日志可以看到Heap size并没有超过4G,所以猜测似乎又不成立
2018-06-01T02:55:17.775+0000: [GC (Allocation Failure) [PSYoungGen: 1507554K->87211K(1993216K)] 2639108K->1237620K(3393024K), 0.2491182 secs] [Times: user=0.29 sys=0.01, real=0.24 secs]
2018-06-01T02:55:36.307+0000: [GC (Allocation Failure) [PSYoungGen: 1564843K->182611K(2011136K)] 2715252K->1384684K(3410944K), 0.6166316 secs] [Times: user=0.61 sys=0.02, real=0.61 secs]
结语
仍然没有验证出OutOfMemory的真实原因,但采用Xmx/Xms来控制内存显然是可以解决问题的,后期再跟踪(附后续)。
参考资料
- http://gdocker.com/3676/dockerdc-osjvm.html
- https://github.com/fabric8io-images/java/issues/6
- https://www.questarter.com/q/java-lang-outofmemoryerror-java-heap-space-when-there-is-allot-of-memory-on-the-docker-machine-27_49536404.html
- https://issues.jboss.org/browse/CLOUD-1537?page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel&showAll=true&_sscc=t
- https://dzone.com/articles/why-my-java-application-is-oomkilled
- https://blog.csanchez.org/2017/05/31/running-a-jvm-in-a-container-without-getting-killed/
记一次OutOfMemory定位过程的更多相关文章
- 记一次OutOfMemory定位过程-续
在前文<记一次OutOfMemory定位过程>完成时最终也没有定位到ECS 中JVM Heap size无法控制的原因,今天再次尝试终于有了一些线索,翻查了ECS的部署脚本发现了memor ...
- $.cookie 使用不了的问题定位过程
最近在项目中需要使用到jquery的cookie,按理说在html头中引入jquery-1.7.1.min.js和jquery.cookie.js,然后在js中就可以使用cookie函数了.像这样使用 ...
- 与PHP5.3.5的战斗----记php5.3.5安装过程
与PHP5.3.5的战斗----记php5.3.5安装过程 摘自:http://blog.csdn.net/lgg201/article/details/6125189这篇文章写的很是不错,,,也是我 ...
- 终于彻底搞清楚了spin-lock 之一次CPU问题定位过程总结
首先这个问题,我只是其中参与者之一.但这个问题很有参考意义,特记录下来. 还有我第一次用"彻底"这个词,不知道会不会有人喷?其实,还有一些问题,也不是特别清楚.比如说什么是CPU流 ...
- 谁记录了mysql error log中的超长信息(记pt-stalk一个bug的定位过程)
[问题] 最近查看MySQL的error log文件时,发现有很多服务器的文件中有大量的如下日志,内容很长(大小在200K左右),从记录的内容看,并没有明显的异常信息. 有一台测试服务器也有类似的问题 ...
- CentOS 7.1系统自动重启的Bug定位过程
[问题] 有同事反应最近有多台MongoDB的服务器CentOS 7.1系统会自动重启,分析了下问题原因. [排查过程] 1. 检查系统日志/var/log/message,并没有记录异常信息,jou ...
- 火焰图--记一次cpu降温过程
引子 正值周末,娃儿6:30又如闹铃般准时来叫醒了我们.年前离开美菜,又回到了杭州.原本是想有更多时间陪伴娃儿,然而新的工作节奏与工作地点,让我们每天都是早上见面:这不,为了周末可以多玩一会儿,早早就 ...
- 开会时CPU 飙升100%同事们都手忙脚乱记一次应急处理过程
告警 正在开会,突然钉钉告警声响个不停,同时市场人员反馈客户在投诉系统登不进了,报504错误.查看钉钉上的告警信息,几台业务服务器节点全部报CPU超过告警阈值,达100%. 赶紧从会上下来,SSH登录 ...
- 记录一次现网MySQL内存增长超限问题定位过程
问题现象现网物理机内存近几日内爆涨使用率超过了90%,可用内存从250G,降低到20G以下,报告警.服务器使用情况来看,并没有什么异常.除了QPS缓慢增长外. MySQL内存分配结构 定位这个问题,先 ...
随机推荐
- 最新的hustoj搭建姿势
试着照某度上的教程搭了一下hustoj,出了一些问题,之前的搭建姿势很多已经不适用了,重新整理一下思路,方法二简单粗暴: 方法一: 首先虚拟机安装了Elementory OS (基于Ubuntu的衍生 ...
- jdk与jre安装之后的名字
jdk与jre安装之后的名字 jdk与jre的区别:https://blog.csdn.net/qq_33642117/article/details/52143824 jdk安装之后的名字: Jav ...
- Android锁屏或灭屏状态下,高速按两次音量下键实现抓拍功能(1.2Framework层使用startService形式实现)
如前一篇博文所分析.我们能够使用广播的形式在高速按下两次音量下键的时候发出广播,以方便client进行捕捉. 既然有两种方式能够实现该Issue那么哪种方式是首选呢? 我个人推荐使用启 ...
- Android Dynamic Action(动态Action)—像访问网页一样地访问Activity
Android Dynamic Action,简称DA,是一种简便.可变Action的实现方案.DA框架的初衷是为了取代Context.startActivity的调用方式,使用建造者模式(Build ...
- C#语言 ArrayList集合
- Hadoop 0.20.2+Ubuntu13.04配置和WordCount測试
事实上这篇博客写的有些晚了.之前做过一些总结后来学校的事给忘了,这几天想又一次拿来玩玩发现有的东西记不住了.翻博客发现居然没有.好吧,所以赶紧写一份留着自己用吧.这东西网上有非常多,只是也不是全然适用 ...
- Java 深拷贝浅拷贝 与 序列化
一.浅拷贝.深拷贝 浅拷贝会对对象中的成员变量进行拷贝:如果是基本类型,拷贝的就是基本类型的值:如果属性是内存地址(引用类型),拷贝的就是内存地址 : 深拷贝,除了基本类型外,引用类型所引用的对象也会 ...
- 取clientdataset detal中的 更新数据, 将detal 转 数据库脚本sql
转自永南博客,更改update 脚本只取变化字段,更改排除blob与数组字段,这两个类型会报错 function vartosql(value: Variant): wideString; var ...
- bzoj3462: DZY Loves Math II
状态很差脑子不清醒了,柿子一直在推错.... ... 不难发现这个题实际上是一个完全背包 问题在于n太大了,相应的有质数的数量不会超过7个 假设要求sigema(1~plen)i pi*ci=n 的方 ...
- 应用程序启动器 “sublime_text.desktop“ 还没有被标记为 信任。如果您不知道这个文件的来源,那么启动它可能会不安全。解决sublime在ubuntu中不支持中文输入问题。
1.下载 git clone https://github.com/lyfeyaj/sublime-text-imfix.git 2.进行一些处理 cd ~/sublime-text-imfix su ...