1.内存溢出

一种通俗的说法。
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.2 解决方法

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

2.内存泄露

Memory Leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点:
1)首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;
2)其次,这些对象是无用的,即程序以后不会再使用这些对象。
如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

关于内存泄露的处理页就是提高程序的健壮型,因为内存泄露是纯代码层面的问题。

泄漏的分类

经常发生:发生内存泄露的代码会被多次执行,每次执行,泄露一块内存;

偶然发生:在某些特定情况下才会发生;

一次性:发生内存泄露的方法只会执行一次;

隐式泄露:一直占着内存不释放,直到执行结束;严格的说这个不算内存泄露,因为最终释放掉了,但是如果执行时间特别长,也可能会导致内存耗尽。

导致内存泄漏的常见原因

1、循环过多或死循环,产生大量对象;

2、静态集合类引起内存泄漏,因为静态集合的生命周期和 JVM 一致,所以静态集合引用的对象不能被释放;下面这个例子中,list 是静态的,只要 JVM 不停,那么 obj 也一直不会释放。

3、单例模式,和静态集合导致内存泄露的原因类似,因为单例的静态特性,它的生命周期和 JVM 的生命周期一样长,所以如果单例对象如果持有外部对象的引用,那么这个外部对象也不会被回收,那么就会造成内存泄漏。

4、数据连接、IO、Socket连接等等,它们必须显示释放(用代码 close 掉),否则不会被 GC 回收。

5、内部类的对象被长期持有,那么内部类对象所属的外部类对象也不会被回收。

6、Hash 值发生改变,比如下面中的这个类,它的 hashCode 会随着变量 x 的变化而变化:

可以看到,在测试方法中,当元素的 hashCode 发生改变之后,就再也找不到改变之前的那个元素了;

这也是 String 为什么被设置成了不可变类型,我们可以放心地把 String 存入 HashSet,或者把 String 当做 HashMap 的 key 值;

当我们想把自己定义的类保存到散列表的时候,需要保证对象的 hashCode 不可变。

7、内存中加载数据量过大;之前项目在一次上线的时候,应用启动奇慢直到夯死,就是因为代码中会加载一个表中的数据到缓存(内存)中,测试环境只有几百条数据,但是生产环境有几百万的数据。

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

内存泄露会最终会导致内存溢出。
相同点:

都会导致应用程序运行出现问题,性能下降或挂起。

不同点:

  1. 内存泄露是导致内存溢出的原因之一,内存泄露积累起来将导致内存溢出。

  2. 内存泄露可以通过完善代码来避免,内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。

3.Java内存泄漏的排查案例

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

3.1确定频繁Full GC现象

首先通过“虚拟机进程状况工具:jps”找出正在运行的虚拟机进程,操作系统的进程ID(PID,Process Identifier)
jps命令格式为:
jps [ options ] [ hostid ]
使用命令如下:

jps:jps -l
ps:ps -aux | grep java

找到你需要监控的ID(假设为28558),再利用“虚拟机统计信息监视工具:jstat”监视虚拟机各种运行状态信息。
jstat命令格式为:
jstat [ option vmid [interval[s|ms] [count]] ]
使用命令如下:
jstat -gcutil 28558 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秒。

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

分析方法通常有两种:
1)把堆dump下来再用工具(Ecplise用MAT插件,Idea安装Jprofiler)进行分析,但dump堆要花较长的时间,并且文件巨大,再从服务器上拖回本地导入工具,这个过程有些折腾,不到万不得已最好别这么干。
也可以把文件上传到网站
堆Dump可视化分析: https://heaphero.io/

2)更轻量级的在线分析,

2.3 定位到代码

举例:

一台生产环境机器每次运行几天之后就会莫名其妙的宕机,分析日志之后发现在tomcat刚启动的时候内存占用比较少,但是运行个几天之后内存占用越来越大,通过jmap命令可以查询到一些大对象引用没有被及时GC,这里就要求解决内存泄露的问题。

Java的内存泄露多半是因为对象存在无效的引用,对象得不到释放,如果发现Java应用程序占用的内存出现了泄露的迹象,那么我们一般采用下面的步骤分析:

1. 登录linux服务器,获取tomcat的pid.

  ps -ef|grep java

2. 用工具生成java应用程序的heap dump(如jmap)

使用“Java内存影像工具:jmap”生成堆转储快照(一般称为headdump或dump文件)。

jmap命令格式:
jmap [ option ] vmid
使用命令如下:jmap -histo:live 28558| head -20

查看存活的对象情况,如下图所示:

生成heap dump文件

  jmap -dump:live,format=b,file=heap.hprof 3514

3. 使用Java heap分析工具(如MAT),找出内存占用超出预期的嫌疑对象

Ecplise用MAT插件
Idea安装Jprofiler进行分析
堆Dump可视化分析: https://heaphero.io/

4. 根据情况,分析嫌疑对象和其他对象的引用关系。

5. 分析程序的源代码,找出嫌疑对象数量过多的原因。

帮助JVM调优的在线工具

Java内存泄漏的排查相关推荐

  1. 一次 Java 内存泄漏的排查

    由来 前些日子小组内安排值班,轮流看顾我们的服务,主要做一些报警邮件处理.Bug 排查.运营 issue 处理的事.工作日还好,无论干什么都要上班的,若是轮到周末,那这一天算是毁了. 不知道是公司网络 ...

  2. jstat 内存泄漏_一次Java内存泄漏的排查!要了自己的老命!

    点击上方"Java之间",选择"置顶或者星标" 你关注的就是我关心的! 作者:枕边书 来源:https://zhenbianshu.github.io 一.由来 ...

  3. java 内存泄露对象排查_记录一次 java内存泄漏的排查

    1.问题:jar进程会随着时间由 30% 上涨到 70% 直到虚机报警.重启过后,还是会缓慢上涨: 进程数也在上涨: 2.在排查内存问题时,可能会使用的命令 1)查看 java 进程:jps -l 可 ...

  4. 分享一次 Java 内存泄漏的排查

    由来 前些日子小组内安排值班,轮流看顾我们的服务,主要做一些报警邮件处理.Bug 排查.运营 issue 处理的事.工作日还好,无论干什么都要上班的,若是轮到周末,那这一天算是毁了. 不知道是公司网络 ...

  5. java内存泄漏问题排查

    背景:程序部署在客户机器上,不定期异常崩溃,且无日错误异常日志记录. day1:初步排查是内存问题导致的,考虑使用分析工具记录分析.另外代码review仔细排查,怀疑有可能跟大量网络socket没有释 ...

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

    转载自  一次恐怖的 Java 内存泄漏排查实战 最近在看<深入理解Java虚拟机:JVM高级特性与最佳实践>(第二版)这本书,理论+实践结合,深入浅出,强烈推荐给大家. 这两天对JVM内 ...

  7. unity如何检测内存泄漏_如何排查Java内存泄漏?看懂这一篇就够用了

    原文:https://www.toptal.com/java/hunting-memory-leaks-in-java 作者:Jose Ferreirade Souza Filho 译者:Emma来源 ...

  8. 什么是内存泄露?该怎么排查?Java内存泄漏策略

    什么是内存泄漏 内存泄漏:对象已经没有被应用程序使用,但是垃圾回收器没办法移除它们,因为还在被引用着. 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的, ...

  9. 透彻分析JAVA内存泄漏和内存溢出的区别

    JAVA内存泄漏和内存溢出的区别和联系 1.内存泄漏memory leak : 是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出. 2 ...

最新文章

  1. 远程登录linux服务器的方式(telnet,ssh,ftp)
  2. WPF实例秀——不用属性也Binding
  3. 函数学习-bool()
  4. 鼠标键盘唤醒计算机,除了按下电源按钮唤醒计算机,WIN10也可以使用鼠标或键盘来唤醒...
  5. 开源客户关系管理系统vTigerCRM 5.2正式版发布
  6. python-利用生成器函数生成斐波那契数列
  7. 【Siddhi】Siddhi的window操作
  8. java swing 按键_Java Swing 快捷键
  9. 解决 placeholder 垂直不居中,偏上的问题
  10. iOS开发技巧:使用Objective-C创建UUID
  11. 2021-0316:梦中明白在作梦
  12. Julia: Dates =DateFormat, format,parse.......
  13. 什么是CMMI能力成熟度模型?企业为什么要做?
  14. 以下哪一个不属于python语言的特点-智慧树知到《Python程序设计基础》章节测试答案...
  15. ImageIO工具类简介及应用
  16. Bluetooth tethering不能用问题
  17. UE4关于材质的几个小技巧
  18. 计算机练打字最难的一段话,电脑盲打字一般练多久 你用多久练会了盲打?
  19. 2021个人年度计划怎么制定?
  20. 要访问1KB的内存为啥需要10位地址线,而不是13位?

热门文章

  1. 人脸识别接口_自助机人脸识别模组集成,双目摄像头,免费活体检测
  2. 《Nmap渗透测试指南》—第6章6.9节MAC地址欺骗
  3. bl系列刀片(blade)服务器,产品技术-HPE Integrity BL870c i6 刀片动能服务器-新华三集团-H3C...
  4. Kinect1代+KinectSDK1.8+OpenNI2.2+NITE2.0+Opencv2.4.10环境配置(2)
  5. SSM框架搭建的步骤
  6. java模拟购物车窗体小程序,微信小程序实现购物车效果 示例源码
  7. 六步搞定苹果iPhone来电铃声自定义
  8. spring cloud学习(四) Fegin 的使用
  9. Idea 配置git
  10. i5-1135G7怎么样 相当于什么水平