1、在解决问题之前,先看下jvm堆内存结构,如下图所示:

对于Java应用,虚拟机管理的内存,可以参考如下图所示:

一般对于一个应用来说,如果内存使用过大,可以从两块来分析,第一:堆内存,第二:堆外内存。下面着重从这两个方面阐述下对最近遇到的内存问题进行分析并解决的过程。

问题详情:

本人负责了一个应用,主要就是定时调度一批接口任务,同时提供一些对外接口,功能很简单,在使用的过程中,逐渐发现了几个内存问题。

1、oom问题,发现一段时间后,应用进程就没了,查看日志提示内存溢出,内存被吃光了,不够分配下个资源使用的空间了。

2、第一个问题解决后,添加了几个功能,发现又出现一些问题:应用运行一段时间后,发现,内存随着时间不段推移,内存占用也越来越多,一般4天后,内使用几乎达到90%,很吓人。

第一个问题解决过程:

oom问题,一般就是程序代码处理不当造成的,有些资源没有释放或者一直在循环开辟某些内存资源。分析这个问题,我使用了本地jvm的一个工具,找到对应的jdk/bin/jvisualvm 工具,它是用来JVM监测、故障排除、分析工具,主要以图形化界面的方式提供运行于指定虚拟机的Java应用程序的详细信息。

1、本地启动程序后,同时打开jvisualvm,在jvisualvm工具可视化页面有多个选项tab,可以根据需求,选择对应的tab进行使用,而我主要对profiler进行了使用,同时发现了问题,进而解决了问题,如下图所示:

这里排查问题,主要对快照功能进行了使用,每隔一段时间进行一次快照(每次快照前,先进行一次手动gc),然后两次快照进行对比差值,进而发现内存不断增长的是哪些对象。

如下图所示,选择第一张和最后一张对比图:

通过以上方法,不断去尝试,一般几个小时候,就能对比出哪些是一直占用内存,且gc也不生效的对象,从而定位类名以及方法,去解决即可。下图是解决后内存的使用情况:

运行个半个月是没有问题的,后面也没有出现oom。

第二个问题解决过程

第二个问题,不好定位,解决的时间比较长,需要长时间不断观察,才会彻底解决。内存一直再涨,但是涨的速度并没有很快,所以用第一种方法不大好分析,因为本地数据并不多,不好分析。通过后面的分析结果,这里涉及两块内存:堆内存,堆外内存。

这次内存不断增长问题,并没有导致应用不可用,出现oom等现象,纯粹是自己隔段时间观察的,下面是解决问题的过程。

1、jvm参数优化

应用运行一段时间,对应用java堆内存的使用进行观察,这里要清楚堆内存结构,通过命令:

jmap -heap pid,可以查看堆内存使用情况,比如:

排查内存问题,jvm优化也能解决一部分问题,所以我先通过优化,再进一步观察,优化的原则,可以参考下图:

通过jvm优化,在gc时间可接受的情况下,配置jvm参数,在观察一段时间。

2、堆内存使用分析

通过jvm优化后,使用命令 jstat -gc pid,查看gc次数,发现gc时间相比之前高了一些,因为应用对实时性要求不高,可以接受,xmx配置比之前多了一倍,应用运行时间长了很多,但是还是会发现,内存在涨的问题,自己继续分析。

通过top命令发现,运行几天后,res内存超过配置的xmx,随着时间推移,res还是再涨。通过jmap -heap pid命令查看堆内存使用情况,发现堆内存占用并不多,远小于res值,说明这里res的内存值多半是堆外内存在占用,于是开始转战对堆外内存的分析。

3、堆外内存分析

在分析堆外内存时,在网上搜了很多。在分析堆外内存时,使用到了jcmd命令,Native Memory Tracking (NMT) 是Hotspot VM用来分析VM内部内存使用情况的一个功能。我们可以利用jcmd(jdk自带)这个工具来访问NMT的数据。

a、在使用jcmd之前,需要配置一些jvm参数,如下如所示:

即:-XX:NativeMemoryTracking=[off | summary | detail] 配置该jvm参数,重启应用即可。

b、通过以上操作,使用命令 jcmd pid VM.native_memory detail scale=MB > a.txt 查看内存的一个使用情况,如下图所示:

这里包含了几个部分,在分析这些内存的时候,需要搞明白啥意思,具体可以参考文章:

https://blog.csdn.net/Developlee/article/details/100691997

c、搞清楚每一项代表的含义,那接下来就是结合自己的代码,分析哪块可能有问题。对于我问题,通过 jcmd pid VM.native_memory baseline 设置基准线,耐心多次 jcmd pid VM.native_memory detail.diff scale=MB > a_diff.txt 看差值,然后得出有可能哪里是问题所在,比如下面是差值的一个截图,这是未解决问题前的一个比较,问题很明显:

从这里就可以看出,线程一直在增加,且资源一直未释放,但是有哪些线程一直在创建申请资源呢,一时也摸不着头绪,所以要知道哪些线程,需要进一步分析。

d、在分析以上问题时,需要查看dump文件,可以通过Jprofile 或者 eclipse mat来分析内存占用情况。

通过jmap -dump pid > m.hprof 发现文件实在是太大,达到3g多,而且还占用着内存,根本从linux上转移不出来,也就无法通过本地idear插件Jprofile 查看,于是使用工具MemoryAnalyzer,根据系统属性,官网下载后,解压即可。

官网地址:http://www.eclipse.org/mat/downloads.php

下载后将包传到linux服务器上解压。

MemoryAnalyzer.ini 配置文件可以修改最大的内存,默认1G基本够用了。

我在使用后,发现java不可用,所以在上面基础上需要配置下面的两部分:-vm -startup,下面是我后来添加的配置:

然后,在linux执行分析命令执行命令

./ParseHeapDump.sh m.hprof  org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components。

m.hprof就是jvm的dump文件,在mat目录下会生成3份.zip结尾的报告和一些m.相关的文件,将生成的m.hprof相关的文件都下载到本地磁盘:

1)使用浏览器

解压缩以.zip结尾的文件,解压后

使用浏览器打开index.html文件内容,查看分析报告,结合前面的分析,着重看下thread的使用情况如下图:

异常thread1:

异常thread2:

看到这里,其实如果对代码熟悉的话,立即知道哪里出问题了,后面修改后,应用发布,在继续观察。

e、按上面修改后,再次观察内存使用,整体发现,会比之前好很多,但是通过jcmd再次对比差值,thread还是再增加,于是再重复d步骤的分析方法,其实这里,如果本地有Jprofile的话,完全可以用该工具打开m.hprof,这次我用本地的Jprofile分析,如下图所示,看到这里,基本知道是啥问题了,修改代码,再次发布,继续跟踪。

d、经过以上几个步骤,观察内存使用情况,发现整体优化非常明显,如下jcmd对比图:

看到这里,真实喜出望外,观察几天后,内存基本稳定了,目前运行良好。

内存问题分析路漫漫,希望这篇文章能够帮助到大家O(∩_∩)O哈哈~

记一次java应用内存不断增长问题解决过程相关推荐

  1. 记一次 JAVA 的内存泄露分析

    记一次 JAVA 的内存泄露分析 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.com/jasonGeng88/blog 当前环境 jdk == 1.8 httpasyn ...

  2. 转:记一次linux oom内存溢出排查过程

    @转:记一次linux oom内存溢出排查过程 记一次linux oom内存溢出排查过程 2018年08月16日 14:13:49 enchanterblue 阅读数 4099更多 分类专栏: --- ...

  3. 记一次linux oom内存溢出排查过程

    一,背景 收到应用服务报警,然后登录上服务器查看原因,发现进程不再了. 二,问题分析 1,那么判断进程被干掉的原因如下: (1),机器重启了 通过uptime看机器并未重启 (2),程序有bug自动退 ...

  4. Go服务迁到K8s后老抽风重启? 记一次完整的线上问题解决过程

    前言 之前把Go服务都迁到Kubernetes上后有些服务的某个 Pod总是时不时的重启一下,通过查业务日志根本查不到原因,我分析了一下肯定是哪里代码不严谨造成引用空指针导致Go发送运行时panic才 ...

  5. WAS集群:记一次Node Agent不活动问题解决过程

    之前很少接触集群,准确地说是很少接触项目现场的实施工作,或者说接触到的都是比较简单的实施工作,安装Linux.WAS.Oracle相对来说都比较简单.一直埋头干着研发的活,干着不要紧,一干就是好几年. ...

  6. 记一次图片压缩内存溢出的问题

    记一次遇见的问题: 起因:Web应用在后台需要展示许多图片,于是页面出现卡顿甚至失去连接.一次性需要加载出60多张1.6M图片. 查看的文章: 1.前端|加载的图片太多或者太大怎么办(上) 2.jav ...

  7. 记一次Java进程突然消失问题

    记一次Java进程突然消失问题 @Date 2017.05.22 现象: 线上同一个应用部署了多台服务器,有的机器运行过程中突然告警,发现服务进程消失. 看程序本身的日志,没有异常输出 查询磁盘空间是 ...

  8. java直接内存为什么快_直接内存与 JVM 源码分析

    直接内存(堆外内存) 直接内存有一种叫法,堆外内存. 直接内存(堆外内存)指的是 Java 应用程序通过直接方式从操作系统中申请的内存.这个差别与之前的堆.栈.方法区,那些内存都是经过了虚拟化.所以严 ...

  9. 使用Java创建内存泄漏

    我刚刚接受采访,并被要求使用Java造成内存泄漏 . 不用说,我对如何开始创建它一无所知. 一个例子是什么? #1楼 最近,我遇到了一种更细微的资源泄漏. 我们通过类加载器的getResourceAs ...

最新文章

  1. ntp 、ntpdate 、chrony 时间同步
  2. 一文揭秘定时任务调度框架quartz
  3. xcode 安装 svn command line
  4. 前端学习(1857)vue之电商管理系统电商系统之登录过程和token
  5. 两个oracle数据库外网同步,利用DBLink+JOB实现两个Oracle数据库之间的数据同步
  6. cocos2d精灵教程(三篇)
  7. python筛选csv数据_pandas数据筛选和csv操作的实现方法
  8. OpenSSL新手自学:如何生成RSA私钥并用于数字签名
  9. html 去除ico,去除html页面中GET《 http://localhost:8080/favicon.ico 404 (Not Found)》
  10. TIM ETR 配置
  11. 卡片游戏 (Throwing cards away I)(队列+模拟)
  12. STM32CubeMX系列|DS18B20温度传感器
  13. Pytest测试用例之setup与teardown方法(一)
  14. html页面虚化,css实现背景虚化效果的示例代码
  15. matlab最炫名族风,Matlab演奏《最炫民族风》
  16. 星加坡php开发_新加坡互联网Offer求建议 - 找工作啦(Job)版 - 北大未名BBS
  17. Excel_VBA开发2048游戏教程——Einsphoton
  18. GaussDB_T 单机版轻量安装
  19. 如何查看Oracle数据库版本
  20. php ldap目录协议,PHP 通过LDAP协议,操作Windows Active Directory

热门文章

  1. 业务需求调研准备工作
  2. 蒸汽弹头 Steam Slug 俄语REPACK版,下载,及其补丁
  3. EVE-NG 添加win7 镜像
  4. 6-2 *显示汉字点阵图形(高级版) (15 分)
  5. 《超能英雄》大结局有点烂
  6. android智能家居使用的协议,基于Android的智能家居APP的设计与实现论文.docx
  7. 萌萌动物连连看在线玩4399html5,超可爱萌物连连看! 《LINE触摸动物》上架
  8. Jsp利用pageoffice实现在线excel文档的编辑并保存到服务器
  9. C#读取泛型变量的值
  10. 【翻译】Densely Connected Convolutional Networks