Java 进程占用内存过多,幕后元凶原来是线程太多
那天中午吃饭,一个同事说,那个项目组的人快气死我了,程序有问题,早晨在群里@了他们,到中午才回消息,然后竟然还说他们的程序没有问题,是我们这边调用的太频繁了。
简直想笑。
背景说明
我们当前这个系统和很多的第三方系统做了集成,出问题的就是其中一个三方系统。其实很简单,他们的系统会产生一些个人待办任务,然后待办任务的个数需要推送到我们的 APP 上,作为图标的角标显示。
用户数据已经打通,其实很简单的需求,角标通知也不要求实时,10分钟刷一次就可以。这个场景非常典型,用消息队列再合适不过了。他们把数据推到消息队列,我们去消息队列取,完美。
可现实并不是这样,他们说系统是产品化,不支持消息队列,只能把待办任务接口开放出来。好的(微笑脸),你们是产品你们有理。可能有待办任务的用户不多,300多个,那就每隔 10 分钟请求 300 多次请求呗。也没用多线程,就是简单的循环 300 多次请求,每次耗时差不多的1分钟。
也可以,那就这样呗。
顺便说一下,这个服务的 JDK 是 1.6 版本,据说由于历史原因,现在已经不敢升级了。而且,服务要部署在 windows 上。(你说神奇不神奇)
花明柳暗
那就这样呗,做个定时任务,10分钟咔咔请求个 300 来次,也挺过瘾,也挺省心。

但是好景不长,天不遂人愿,服务器不遂程序员愿。
以下是同事的经历,我转述以下。
就在定时任务跑起来后的第二个晚上,那本来该是一个平常的晚上,可是告警邮件扰人清梦。一看日志,内存使用空间过高,撑爆了,导致机器自动重启了。windows 就这点好啊,还会自动重启(尴尬脸)。然后手动上去把服务启动起来,解决。
隔了一天,还是晚上,又报警了,服务器又自动重启了,又是内存使用空间过高。又手动上去把服务启动了。
于是他反馈给这个服务的开发人员,结果得到的回复是:“我们的服务没有问题,肯定是你们的调用有问题,你们把定时任务停掉肯定就好了,所以是你们的问题”。
于是,他过来找我,跟我说明情况,问我可能会是什么问题。
我:你确定定时服务是 10 分钟一次,没有出现死循环吗?
同事:确定。
我:那他们的服务有使用 redis 之类的外部缓存吗?
同事:不知道。
我:。。。 既然你确定你调用的没问题,那肯定是他们程序出现问题把内存撑爆了呀,这有什么好怀疑的,让他们改吧。
同事:他们现在说自己没问题啊。
挖出真凶
好吧,既然他们说没问题,那我就来帮他把问题找出来吧。于是,远程进了那台 windows 服务器。
这时候已经把定时任务已经跑了两天了,16G 的内存已经用掉 15G 多了,眼看随时有可能崩溃,然后把定时任务停掉,内存使用量也并不会下来。
我开始怀疑是不是用了 redis 之类的外部缓存,结果进服务器一查 redis 、memcached 之类的压根儿就没装,所以基本排除外部缓存。
并且登录上去之后查看进程内存占用,确实就是一个 Java 进程占了这么多内存。
那既然不是外部缓存,那肯定出在 JVM 上了,要不然就是用了 JVM 缓存,要不然就是内存泄漏什么的。于是我想用 jinfo -flags看一下 JVM 初始参数,JDK 6 竟然还不支持 -flags 。
然后我不知道是不是尝试了 jmap -heap 还是就看了一眼 jmap -help以为不支持 jamp -heap,反正最后我是通过 jconsole来观察的 JVM。一看 JVM 参数明显就是默认没特殊设置过,并且奇怪的是对内存一共采用了 700 多M。700M 和 15G 比,差哪儿去了,没道理啊,问题没出在堆上。
然后我尝试执行 GC 操作,然而并没有任何改善。直到这里,我严重怀疑是出现了内存泄漏了。
于是我执行了 jmap -dump,把堆、线程信息 dump 下来,然后拉到本地分析。不看不知道,一看吓一跳,线程多到令人窒息。

不得不说,有一点他们做的非常好,竟然贴心的给线程编了号,没错,就是有这么多线程 10万多个。于是我们算了一下假设 10分钟请求 300 次,那就是 300 个线程,一小时就是 30 x 6=1800,一天24小时就是1800 x 24=43200,两天多的时间 10万多个线程那就正好对上了,好牛x的样子。
一个线程默认占用空间大小 1M,10万多个线程那就是 10个多G,加上堆内存占用和机器上其他服务的内存占用,内存飙到 15G 就对的上了。
谁的问题谁处理
有问题就找问题就这么难吗,不承认自己的程序有问题是怎么想的呢。
好啊,你们自己不查,我帮你找到问题原因了,满意了吧。
于是,同事理直气壮的把上面那张截图发给他们,但是没有额外说一句话。
下午,微信群里对方发来消息,问题已修改,可以再试试。
然后,好多天过去了,问题没有再出现。
规避问题
有的同学问了,系统能创建10万多个线程吗,有可能的。这篇文章是「你假笨」大神写的 Linux 系统下能创建多少个线程的源码分析 https://club.perfma.com/article/244079,有兴趣可以上去看一看。
这个问题产生的原因就是线程创建了但是没有销毁,估计是销毁逻辑写的有些问题吧。
抛开逻辑错误不说,使用线程的正确做法是使用线程池,以免带来不必要的性能损耗和这种未加控制、未及时销毁带来的线程无止境创建的问题。

Java 进程占用内存过多,幕后元凶原来是线程太多的更多相关文章
- Java进程占用内存过高,排查解决方法
最近收到邮件报警,说内存使作率达到84%.如下图: 解决方法: A:可能是代码原因导致的问题: 1.使用命令:top 查看当前进程的状态 2.从上图可以看到PID:916的java进程占用内存较大.定 ...
- Java进程占用系统内存较高的排查方法
1.通过top 查看具体是哪个进程占用内存较多 Tasks: 65 total, 1 running, 64 sleeping, 0 stopped, 0 zombie %Cpu(s): 2.0 us ...
- Java进程占用CPU资源过多分析
问题描述: 生产环境下的某台tomcat7服务器,在刚发布时的时候一切都很正常,在运行一段时间后就出现CPU占用很高的问题,基本上是负载一天比一天高. 问题分析: 1,程序属于CPU密集型,和开发沟通 ...
- java进程占用系统内存高,排查解决
转自:http://blog.51cto.com/chengxiaobai/2052530?cid=695076 故障:最近收到生产服务器的报警短信以及邮件,报警内容为:内存使用率高于70%. 使用t ...
- Linux的php-fpm优化心得-php-fpm进程占用内存大和不释放内存问题(转)
原文地址:https://wzfou.com/php-fpm/ 最近发现博客的内存老是隔三差五地被“吃掉”了,登录到后台后偶尔会出卡顿的情况,一开始怀疑是Swap不够导致的,于是给VPS主机增加了几个 ...
- 显示所有APP的进程详细信息(进程ID、进程所在UID、进程占用内存、进程名)
main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:and ...
- 万答#3,MGR最佳配置参考,PFS里的监测指标要全开吗,mysqld进程占用内存过高怎么排查
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 问题1,有推荐的MGR运行最佳配置参考吗 在「3306π」社区广州站5月22日的分享会上,万里数据库CTO娄帅给出了他建议 ...
- Linux中查看进程占用内存的情况【转】
转自:http://hutaow.com/blog/2014/08/28/display-process-memory-in-linux/ Linux中查看某个进程占用内存的情况,执行如下命令即可,将 ...
- 灵魂拷问:Java对象的内存分配过程是如何保证线程安全的?(阿里面试)
JVM内存结构,是很重要的知识,相信每一个静心准备过面试的程序员都可以清楚的把堆.栈.方法区等介绍的比较清楚. 上图,是一张在作者根据<Java虚拟机规范(Java SE 8)>中描述的J ...
随机推荐
- C++调用Lua编程环境搭建及测试代码示例
C++调用Lua编程环境搭建及测试代码示例 摘要:测试环境是VS2005+LuaForWindows_v5.1.4-45.exe+WIN7 1.安装lua开发环境LuaForWindows_v5.1. ...
- codeforces 609C
#include<bits/stdc++.h> using namespace std; ],c[]; int main() { int n,i; while(cin >> n ...
- JPA多对一单向关联
在实际开发过程中,JPA多对一单向关联是使用最多的关联方式. 下面是订单与订单项的配置关系. 订单(Order):一的一方,不进行任何配置 @Entity @Table(name="orde ...
- [转]ECMAScript 2016,2017 和 2018 中所有新功能的示例
很难追踪 JavaScript(ECMAScript)中的新功能. 想找到有用的代码示例更加困难. 因此,在本文中,我将介绍 TC39 已完成 ES2016,ES2017 和 ES2018(最终草案) ...
- UVa 10603 Fill [暴力枚举、路径搜索]
10603 Fill There are three jugs with a volume of a, b and c liters. (a, b, and c are positive intege ...
- 【踩坑记录】vue单个组件内<style lang="stylus" type="text/stylus" scoped>部分渲染失效
vue组件化应用,近期写的单个组件里有一个的渲染部分样式渲染不上去 因为同结构的其他组件均没有问题,所以排除是.vue文件结构的问题,应该是<style>内部的问题 <style l ...
- 11-28-----vertor和list使用场景
1.vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随机访问,而不子啊胡插入和删除的效率,使用vector, 2.list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关 ...
- Canvas学习实践:一款简单的动画游戏
最近学习了下Canvas绘图...突发奇想就有了下面这款简单的小游戏,纯属娱乐~ 废话不多说,直接上代码: <!DOCTYPE html> <html lang="zh&q ...
- 用C++获取屏幕上某点的颜色
假定坐标点 x=50,y=50. 输出 RGB 用 16 进制数.Afxwin.h 你建项目时可得.#include <Afxwin.h>#include <Windows.h> ...
- Mybase desktop7.3破解
1.Mybase Desktop 7.3 安装包 百度云链接: 链接:https://pan.baidu.com/s/1mWZ2_Qmkf6aAX9CYgrN12A 提取码:vjw7 2.破解包 百度 ...