作者:小怪聊职场
https://www.jianshu.com/p/454...
最近在看《深刻了解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 spacetomcat:java.lang.OutOfMemoryError: Java heap spaceweblogic:Root cause of ServletException java.lang.OutOfMemoryErrorresin:java.lang.OutOfMemoryErrorjava: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,我没有应用过。
近期热文举荐:
1.600+ 道 Java面试题及答案整顿(2021最新版)
2.终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!
3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!
5.《Java开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!