一则JVM memory leak解决的过程
起因是我们的集群应用(3台机器)新版本测试过程中,一般的JVM内存占用 都在1G左右, 但在运行了一段时间后,慢慢升到了4G, 这是一个明显不正常的现象。
定位 过程:
1.先在该机器上按照步骤尝试重现现场,当发生问题后打开一台机器上JDK的jvisualvm观察JVM内存占用情况,这时明显看到GC很密集,锯齿线很密,几乎压在一起。之后随着时间增加,
Heap曲线缓步上升。 这时怀疑是哪里的代码出现了死循环, 产生了大量的垃圾对象频繁被GC。
JVM启动的主要参数为-Xms1024M -Xmx1096M -XX:MaxPermSize=512M -Xmn512M -Xss512k -XX:+UseParallelGC

这里能看到频繁GC后heap直线上升,接近分配的heap上限。

2.这时尝试dump了heap和thread:
jps查看pid
jmap -dump:format=b,file=HeapDump.hprof pid
jstack pid > threaddump.txt
用TDA打开thread dump试图分析有无一些死锁资源竞争问题,并没有看到有死锁的报告,但看到一个可疑的大部分操作都在等待monitor的问题。

看了下大部分sleep thread都卡在java.util.Vector上,应该是某些IO操作导致的底层问题。
"TheadPool:AuditLookup:Waiting" prio= tid=0x0000000008e8c800 nid=0x968 in Object.wait() [0x000000000e45f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000c20d42d0> (a java.util.Vector)
at com.***.util.BlockingQueue.remove(BlockingQueue.java:)
- locked <0x00000000c20d42d0> (a java.util.Vector)
at com.***.util.ThreadPool$PooledThread.run(ThreadPool.java:)
Locked ownable synchronizers:
- None
3.拿到hprof后,用IBM贡献的开源工具Eclipse Memory Analyzer,打开Leak report看一下overview

从这里大概可以看见占用比较多的是byte[], 占了75%, 下面看一下details的信息。
4.下面显示的是向内存聚集点的一个common path,这里能找到的信息就比较多了,可以看到是这个Message有关的service引起的,这个service调用了
序列化流ObjectInputStream, 然后在它的HandleTable中保存了大量的二进制byte数组。截图去掉了一些包名。

由于是这个Message的服务调用了下层JDK的ObjectInputStream,怀疑是这里出了什么问题。看了一下有关的介绍和ObjectInputStream内部HandleTable的代码,
HandleTable是用来接收流的。一些主要的代码片段如下
HttpURLConnection huc= ( HttpURLConnection )new URL( url).openConnection();
ObjectInputStream ois = new ObjectInputStream( huc.getInputStream() );
ois.readUTF();
ois.readObject();
很简单,就是打开输入流,读入string与对象,没什么特别的, 这样的东西也会有什么问题?继续查,看到一些文章说ObjectInputStream会有memory leak的风险,分析了下
似乎这里并不是问题的起点,ObjectInputStream只有被滥用时才有可能。 这样回到业务代码上继续看,因为有三台机连在一起时才会这样, 2台机就不会, 所以继续查log,
用command line的方式启动应用, 发现时send message的方法在刷屏, 两台机不停的在互发, 这时观察一下系统的网络占用:

可以看到该机器A 网络从一个较低的send <100Kbps的速率直线上升到1.1Mbps, 是个很明显的广播风暴, 另一台机B也是这样, 第三台机C并没有什么明显的网络
波动。
看来明显是消息的分发逻辑出了问题,这里简单介绍一下目前的消息分发逻辑,不然就无法解释怎么解决的了。消息分发是被改动过的了,之前的逻辑是这样:
集群中有一个主机(A),其它都是分机(B,C),当 有消息从分机(B)中发出时,A会判断消息类型,如果是广播型则向A中保存的所有分机列表进行广播(步骤2,3)

这个过程中B会判断消息来源是否是自己,反正重复循环发。C如果想向B发消息,只能先向主机A发,由A来转发给B。
而这个逻辑被这次升级改动打破了,这个封闭的消息组加入了一个新的消息主机,这个主机会有自己对应的几个分机,组成了另一个消息分发环,而发消息的时候并没有考虑这个新的主机,图如下:

当B向A发消息后,主机A的设计就是想其所有分机(B,C,D)分发消息,所以另一组消息主机D也被认为是A的分机,B的消息被传播到D,D接到后检查自己的分机(E,F,A),
向A又回发了这个消息(步骤3),这时A与D之间就会不停地互相转发源头是B的消息,造成了大量的消息对象产生及销毁,内存波动及网络拥堵。
根据逻辑改动过两个消息主机A,D的分发机制后,问题解决, 内存GC回归正常, 网络流量也回落了。

一则JVM memory leak解决的过程的更多相关文章
- quartzScheduler_Worker-1] but has failed to stop it. This is very likely to create a memory leak解决
01-Jul-2016 07:24:20.218 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 80 ...
- 大神的---解决tomcat内存溢出问题----tomcat报错:This is very likely to create a memory leak问题解决
tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一 ...
- 解决:The web application [] registered the JDBC driver [] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
问题描述 在将Spring Boot程序打包生成的war包部署到Tomcat后,启动Tomcat时总是报错,但是直接在IDEA中启动Application或者用"java -jar" ...
- WPF WebBrowser Memory Leak 问题及临时解决方法
首先介绍一下内存泄漏(Memory Leak)的概念,内存泄露是指程序中已动态分配的堆内存由于某种原因未释放或者无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果. 最近在使用W ...
- Android 常见 Memory Leak 原因及解决办法总结
待整理: http://geek.csdn.net/news/detail/50692 背景 在Android开发过程中,我们经常碰到的情况就是在我们不清楚为什么情况下,程序突然出现Crash了.其中 ...
- elasticsearch报错[WARN ][bootstrap ] Unable to lock JVM Memory: error=12,reason=Cannot allocate memory,解决
早上在服务器上安装elasticsearch集群,在其中的一台上面安装好elasticsearch之后安装了一些插件,其中一个插件是marvel,结果可能是新版本不支持这个插件,就没有安装成功,也就索 ...
- tomcat报错:This is very likely to create a memory leak问题解决
tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一 ...
- <实战> 通过分析Heap Dump 来了解 Memory Leak ,Retained Heap,Shallow Heap
引入: 最近在和别的团队的技术人员聊天,发现很多人对于堆的基本知识都不太熟悉,所以他们不能很好的检测出memory leak问题,这里就用一个专题来讲解如何通过分析heap dump文件来查找memo ...
- malloc(50) 内存泄露 内存溢出 memory leak会最终会导致out of memory
https://en.wikipedia.org/wiki/Memory_leak In computer science, a memory leak is a type of resource l ...
随机推荐
- 两种状态显示处理. enum , Linq AsEnumerable
1.ENUM protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { GridViewRow ro ...
- JavaScript常用函数之Eval()使用
eval() 功能:首先解释Javascript代码 然后执行它 用法:Eval(codeString) codeString是包含有javascript语句的字符串,在eval之后使用Javasc ...
- ElasticSearch学习-centos下安装
1.安装java运行环境(jre) //这里我安装了jdk 其实只需要安装jre就可以了 0)cd /usr;mkdir /usr/java; cd java 1)wget http://downlo ...
- maven 环境的配置 JAVA_HOME not found in your envirnment
maven 的环境配置在配置maven前 先做好java的环境配置现在假定java已经配置好了.在环境变量中添加;maven的解压路径\bin 例如:D:\soft\java\apache-maven ...
- visual studio 2005 常用按键
VS2005 实用快捷键,迅速提高代码编写效率! 代码快捷键 Ctrl+J / Ctrl+K,L 列出成员 Ctrl+Shift+空格键 / Ctrl+K,P 参数信息 Ctrl+ ...
- 最喜欢的算法(们) - Levenshtein distance
String Matching: Levenshtein distance Purpose: to use as little effort to convert one string into th ...
- javascript变量问题
CMAScript变量包含两种不同数据类型的值: 基本类型值:简单的数据段:引用类型值:可能有多个值构成的对象. 5种基本类型:Undefined,Null,Bollean,Number,String ...
- "巴卡斯杯" 中国大学生程序设计竞赛 - 女生专场
Combine String #include<cstdio> #include<cstring> #include<iostream> #include<a ...
- 基于VC的ACM音频编程接口压缩Wave音频(三)
(三)音 频 数 据 的 压 缩 下 面 说 明 使 用 CODEC 实 现 音 频 压 缩 的 过 程:假 设 源 信 号 为8K 采 样.16bits PCM 编 码. 单 声 道. 长 度 为1 ...
- mottoes
1. You don't kown if you can until a try. 2. Rule youself. 3. It's what you do in the dark that puts ...