一次恐怖的 Java 内存泄漏排查实战

转载自  一次恐怖的 Java 内存泄漏排查实战

最近在看《深入理解Java虚拟机:JVM高级特性与最佳实践》(第二版)这本书,理论+实践结合,深入浅出,强烈推荐给大家。


这两天对JVM内容进行了一个讨论,讨论的内容主要包括如下几个方面。
1)内存溢出和内存泄露的介绍?
2)如何排查和处理内存泄露?

 

一、内存溢出和内存泄露

一种通俗的说法。
1、内存溢出:你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数据,出现溢出。
2、内存泄漏:你用new申请了一块内存,后来很长时间都不再使用了(按理应该释放),但是因为一直被某个或某些实例所持有导致 GC 不能回收,也就是该被释放的对象没有释放。点击此处查看内存泄漏更多说明。

 

下面具体介绍。

1.1 内存溢出

java.lang.OutOfMemoryError,是指程序在申请内存时,没有足够的内存空间供其使用,出现OutOfMemoryError。点击此处查看内存泄漏更多说明。


产生原因
产生该错误的原因主要包括:

  • JVM内存过小。

  • 程序不严密,产生了过多的垃圾。

     

程序体现
一般情况下,在程序上的体现为

  • 内存中加载的数据量过于庞大,如一次从数据库取出过多数据。

  • 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收。

  • 代码中存在死循环或循环产生过多重复的对象实体。

  • 使用的第三方软件中的BUG。

  • 启动参数内存值设定的过小。

     

错误提示
此错误常见的错误提示:

tomcat:java.lang.OutOfMemoryError: PermGen space
tomcat:java.lang.OutOfMemoryError: Java heap space
weblogic:Root cause of ServletException java.lang.OutOfMemoryError
resin:java.lang.OutOfMemoryError
java:java.lang.OutOfMemoryError

 

解决方法

1)增加JVM的内存大小
对于tomcat容器,找到tomcat在电脑中的安装目录,进入这个目录,然后进入bin目录中,在window环境下找到bin目录中的catalina.bat,在linux环境下找到catalina.sh。
编辑catalina.bat文件,找到JAVA_OPTS(具体来说是 set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER%")这个选项的位置,这个参数是Java启动的时候,需要的启动参数。
也可以在操作系统的环境变量中对JAVA_OPTS进行设置,因为tomcat在启动的时候,也会读取操作系统中的环境变量的值,进行加载。
如果是修改了操作系统的环境变量,需要重启机器,再重启tomcat,如果修改的是tomcat配置文件,需要将配置文件保存,然后重启tomcat,设置就能生效了。

2)优化程序,释放垃圾
主要思路就是避免程序体现上出现的情况。避免死循环,防止一次载入太多的数据,提高程序健壮型及时释放。因此,从根本上解决Java内存溢出的唯一方法就是修改程序,及时地释放没用的对象,释放内存空间。

 

1.2 内存泄露

Memory Leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。


在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点。
1)首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;
2)其次,这些对象是无用的,即程序以后不会再使用这些对象。


如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

关于内存泄露的处理页就是提高程序的健壮型,因为内存泄露是纯代码层面的问题。点击此处查看内存泄漏更多说明。

 

1.3 内存溢出和内存泄露的联系

内存泄露会最终会导致内存溢出。

相同点:都会导致应用程序运行出现问题,性能下降或挂起。
不同点:1) 内存泄露是导致内存溢出的原因之一,内存泄露积累起来将导致内存溢出。2) 内存泄露可以通过完善代码来避免,内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。

 

二、一个Java内存泄漏的排查案例

某个业务系统在一段时间突然变慢,我们怀疑是因为出现内存泄露问题导致的,于是踏上排查之路。

2.1 确定频繁Full GC现象

首先通过“虚拟机进程状况工具:jps”找出正在运行的虚拟机进程,最主要是找出这个进程在本地虚拟机的唯一ID(LVMID,Local Virtual Machine Identifier),因为在后面的排查过程中都是需要这个LVMID来确定要监控的是哪一个虚拟机进程。


同时,对于本地虚拟机进程来说,LVMID与操作系统的进程ID(PID,Process Identifier)是一致的,使用Windows的任务管理器或Unix的ps命令也可以查询到虚拟机进程的LVMID。


jps命令格式为:
jps [ options ] [ hostid ]
使用命令如下:
使用jps:jps -l


使用ps:ps aux | grep tomat 找到你需要监控的ID(假设为20954),再利用“虚拟机统计信息监视工具:jstat”监视虚拟机各种运行状态信息。

 

jstat命令格式为:
jstat [ option vmid [interval[s|ms] [count]] ]
使用命令如下:
jstat -gcutil 20954 1000
意思是每1000毫秒查询一次,一直查。gcutil的意思是已使用空间站总空间的百分比。


结果如下图:

 

 

jstat执行结果

查询结果表明:这台服务器的新生代Eden区(E,表示Eden)使用了28.30%(最后)的空间,两个Survivor区(S0、S1,表示Survivor0、Survivor1)分别是0和8.93%,老年代(O,表示Old)使用了87.33%。程序运行以来共发生Minor GC(YGC,表示Young GC)101次,总耗时1.961秒,发生Full GC(FGC,表示Full GC)7次,Full GC总耗时3.022秒,总的耗时(GCT,表示GC Time)为4.983秒。

 

2.2 找出导致频繁Full GC的原因

分析方法通常有两种:
1)把堆dump下来再用MAT等工具进行分析,但dump堆要花较长的时间,并且文件巨大,再从服务器上拖回本地导入工具,这个过程有些折腾,不到万不得已最好别这么干。


2)更轻量级的在线分析,使用“Java内存影像工具:jmap”生成堆转储快照(一般称为headdump或dump文件)。
jmap命令格式:
jmap [ option ] vmid
使用命令如下:
jmap -histo:live 20954
查看存活的对象情况,如下图所示:

 

 

存活对象

按照一位IT友的说法,数据不正常,十有八九就是泄露的。在我这个图上对象还是挺正常的。

我在网上找了一位博友的不正常数据,如下:

 

可以看出HashTable中的元素有5000多万,占用内存大约1.5G的样子。这肯定不正常。

 

2.3 定位到代码

定位带代码,有很多种方法,比如前面提到的通过MAT查看Histogram即可找出是哪块代码。——我以前是使用这个方法。也可以使用BTrace,我没有使用过。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326950.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET与ASP.NET Core用户验证Cookie并存解决方案

在你将现有的用户登录(Sign In)站点从ASP.NET迁移至ASP.NET Core时,你将面临这样一个问题——如何让ASP.NET与ASP.NET Core用户验证Cookie并存,让ASP.NET应用与ASP.NET Core应用分别使用各自的Cookie?因为ASP.NET用的是…

vue学习2

P1 01_Vue学习目标03:50 P2 02_前端知识体系16:27 P3 03_前后端分离的演变史17:13 P4 04_前端MVVM模式09:31 P5 05_Vue是什么07:23 P6 06_第一个Vue应用程序07:06 P7 07_Vue实例声明周期05:35 P8 08_条件渲染06:59 P9 09_列表渲染03:34 P10 10_事件处理03:44…

一道非常棘手的 Java 面试题:i++ 是线程安全的吗

转载自 一道非常棘手的 Java 面试题:i 是线程安全的吗 i 是线程安全的吗? 相信很多中高级的 Java 面试者都遇到过这个问题,很多对这个不是很清楚的肯定是一脸蒙逼。内心肯定还在质疑,i 居然还有线程安全问题?只能说…

Microsoft规划了.NET的未来发展

Microsoft的Mads Torgersen分享了.NET语言家族的更新策略,给出了对公司未来的功能考虑的深刻理解。虽然C#、VB.NET和F#的开发是通过GitHub公开进行的,但是Microsoft的长远规划却经常是保密的。公众如果对Microsoft目前思考问题的方式有相关的意见和建议的…

逆波兰计算器实现

逆波兰计算器 思路分析 代码实现 package com.atguigu.stack;import java.security.AlgorithmConstraints; import java.util.ArrayList; import java.util.List; import java.util.Stack;/*** 创建人 wdl* 创建时间 2021/3/20* 描述*/ public class PolandNotation {public …

逆波兰表达式中缀表达式转换为后缀表达式

中缀表达式转换为后缀表达式 思路分析 代码实现 package com.atguigu.stack;import javax.swing.plaf.nimbus.State; import java.security.AlgorithmConstraints; import java.util.ArrayList; import java.util.List; import java.util.Stack;/*** 创建人 wdl* 创建时间 20…

OSS.Common扩展.Net Standard支持实例分享

上篇(.Net基础体系和跨框架开发普及)介绍了.Net当前生态下的大概情况,也分享了简单实现的过程,这篇文章就是讲解我的OSS.Common项目扩展.Net Standard 支持的过程,主要集中在:方案的选择,移植检…

A configuration error occurred during startup.Please verify the preference field with the prompt: To

今天遇到了一个棘手的问题,到现在都没有解决,折腾了一天结果捣鼓出来个更棘手的问题,经过多方继续折腾,终于把后来的这个问题给搞定了,但是前面的问题还是没有解决。有遇到相类似的问题解决了的麻烦分享一下&#xff0…

150. 逆波兰表达式求值---JAVA---LeetCode

class Solution {public int evalRPN(String[] tokens) {//创建一个栈&#xff0c;只需要一个栈即可Stack<Integer> stack new Stack<>();//遍历 lsfor(String item:tokens){//这里使用正则表达式来取出数if(isNumber(item)){//匹配的是多位数//入栈stack.push(In…

look look C#7

vs2017也rc好几个版本了&#xff0c;本想跟进看看c#7加入了什么内容&#xff0c;去搜索c#7&#xff0c;确实找到了不少文章&#xff0c;无奈很多特性ide根本不让编译啊。。。所以今天主要列出已经确定了的c#7特性&#xff08;一般来说rc后也不会加入新的特性了&#xff0c;其它…

jQuery Raty星级评分插件使用方法

转载自 jQuery Raty星级评分插件使用方法 使用jQuery Raty&#xff0c;可以很方便的在页面上嵌入一个评分组件&#xff0c;如下所示&#xff1a; 使用方法很简单&#xff0c;首先从https://github.com/wbotelhos/raty下载raty的源代码&#xff08;依赖于jquery&#xff09; …

迷宫问题---递归解决

题目描述 代码实现 package com.atguigu.recursion;/*** 创建人 wdl* 创建时间 2021/3/21* 描述*/ public class MiGong {public static void main(String[] args) {//先创建一个二维数组&#xff0c;模拟迷宫//地图int[][] map new int[8][7];//使用1表示墙//上下全部置为1f…

20周年献礼:Visual Studio 2017正式版3月7日发布

微软透露 Visual Studio 2017 的开发工作已经接近尾声&#xff0c;即将进入 RTM 阶段。现在&#xff0c;微软正式宣布&#xff0c;Visual Studio 2017 正式版将于 3 月 7 日正式发布&#xff01;值得一提的是&#xff0c;今年正好是 Visual Studio 诞生 20 周年纪念。 为了表示…

JDK环境变量配置(一次性成功)

1.变量名&#xff1a; JAVA_HOME 变量值&#xff1a;&#xff08;变量值填写你的jdk的安装目录&#xff0c;例如本人是 E:\Java\jdk1.8.0&#xff09; 2.变量名&#xff1a; Path 变量值&#xff1a; ;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; 3.变量名&#xff1a; CLASSPATH …

jquery插件star-rating.js实现星级评分特效

转载自 jquery插件star-rating.js实现星级评分特效 Bootstrap Star Rating是一个简单而强大的jQuery插件实现星级分数评级。支持像分数星填充和RTL输入先进的功能。在利用纯CSS-3造型使控制重点开发。该插件使用引导标记和造型默认情况下&#xff0c;但它可以覆盖与其他任何C…

C#winforms实现windows窗体人脸识别

在之前我写过一篇博客&#xff0c;是关于javaweb实现人脸识别&#xff0c;包括数据库以及java源码&#xff0c;还有相关的jar包都已经上传了&#xff0c;有想要了解的可以去看看&#xff0c;地址是&#xff1a;java实现人脸识别源码 实现了之后又正好朋友开发C#&#xff0c;想要…

OSS.Common获取枚举字典列表标准库支持

上篇&#xff08;.Net Standard扩展支持实例分享&#xff09;介绍了OSS.Common的标准库支持扩展&#xff0c;也列举了可能遇到问题的解决方案。由于时间有限&#xff0c;同时.net standard暂时还没有提供对DescriptionAttribute的支持&#xff0c;所以其中的转化枚举到字典列表…

程序员的情人节礼物:当天微软开始Build 2017登记

2016 年 12 月&#xff0c;微软曾经宣布 Build 2017 大会将于 2017 年 5 月 10 日至 12 日在美国西雅图举行&#xff1b;时隔两个月&#xff0c;关于 Build 2017 大会的消息&#xff0c;终于有了新的进展。 2 月 10 日&#xff0c;微软在官方博客中宣布 Build 2017 大会将开启注…