起因是我们的集群应用(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解决的过程的更多相关文章

  1. 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 ...

  2. 大神的---解决tomcat内存溢出问题----tomcat报错:This is very likely to create a memory leak问题解决

    tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因  在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一 ...

  3. 解决: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" ...

  4. WPF WebBrowser Memory Leak 问题及临时解决方法

    首先介绍一下内存泄漏(Memory Leak)的概念,内存泄露是指程序中已动态分配的堆内存由于某种原因未释放或者无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果. 最近在使用W ...

  5. Android 常见 Memory Leak 原因及解决办法总结

    待整理: http://geek.csdn.net/news/detail/50692 背景 在Android开发过程中,我们经常碰到的情况就是在我们不清楚为什么情况下,程序突然出现Crash了.其中 ...

  6. elasticsearch报错[WARN ][bootstrap ] Unable to lock JVM Memory: error=12,reason=Cannot allocate memory,解决

    早上在服务器上安装elasticsearch集群,在其中的一台上面安装好elasticsearch之后安装了一些插件,其中一个插件是marvel,结果可能是新版本不支持这个插件,就没有安装成功,也就索 ...

  7. tomcat报错:This is very likely to create a memory leak问题解决

    tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因  在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一 ...

  8. <实战> 通过分析Heap Dump 来了解 Memory Leak ,Retained Heap,Shallow Heap

    引入: 最近在和别的团队的技术人员聊天,发现很多人对于堆的基本知识都不太熟悉,所以他们不能很好的检测出memory leak问题,这里就用一个专题来讲解如何通过分析heap dump文件来查找memo ...

  9. 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 ...

随机推荐

  1. 如何用VB.Net创建一个三层的数据库应用程序

    [b]1.[/b][b]概论:[/b] 本文将介绍如何创建一个三层应用程序,并且将介绍如何创建一个Web Service服务. ADO.NET创建Windows三层结构应用程序的体系架构如下图所示: ...

  2. Java 第22章 mySQy

    下列都是关系型数据库(在数据库中存在行.列) oracle: Oracle公司的产品(被sun公司收购) 中大型项目使用.银行系统.政府办公系统 9i/10g/11g sql server: 微软公司 ...

  3. 使用Wireshark 查看查找未被过滤端口

    打开Wireshark ,过滤输入“ip.src == [IP] && ip.ttl < 255”,因为防火墙伪造的数据包的TTL都是255,真实的数据包应该是56,所以这句话直 ...

  4. #笔记# 移动前端开发之viewport

    一般移动设备的浏览器都默认设置了一个 viewport ,并初始定义一个虚拟的layout viewport(布局视口),用于解决早期的页面在手机上显示的问题.下面我们来认识几个与 viewport  ...

  5. Linq-分组统计

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...

  6. 位图图像处理控件ImageCapture Suite更新至v9.1

    概述:Dynamsoft公司旗下非常出名的位图图像处理控件ImageCapture Suite更新至了v9.1,这次新版本为Mac版本和IE 9新增了不少功能,同时还对其他组件的性能进行了质的提高! ...

  7. <<数字是世界的>>读后感

    我对这本书的第一印象就是很多书评中提到的,这是一本无论是否有学习过计算机专业知识的人都可以读的书.我一开始不是很能理解这些评价,我是抱着对这个问题的疑惑进行通读的,以后我发现了,它全书中都很少出现计算 ...

  8. Top ShooterHDU2863&&继续xxx定律HDU3784

    继续xxx定律 HDU3784 先看这个题目:HDU3782 #include<iostream> #include<algorithm> #include<stdio. ...

  9. hdu 4193 - Non-negative Partial Sums(滚动数列)

    题意: 给定一个由n个整数组成的整数序列,可以滚动,滚动的意思就是前面k个数放到序列末尾去.问有几种滚动方法使得前面任意个数的和>=0. 思路: 先根据原来的数列求sum数组,找到最低点,然后再 ...

  10. html+css实现简易下拉菜单

    <!DOCTYPE html> <html> <head> <style> div { width:100px; height:40px; overfl ...