37 | Tomcat内存溢出的原因分析及调优
李号双
该思维导图由 AI 生成,仅供参考
作为 Java 程序员,我们几乎都会碰到 java.lang.OutOfMemoryError 异常,但是你知道有哪些原因可能导致 JVM 抛出 OutOfMemoryError 异常吗?
JVM 在抛出 java.lang.OutOfMemoryError 时,除了会打印出一行描述信息,还会打印堆栈跟踪,因此我们可以通过这些信息来找到导致异常的原因。在寻找原因前,我们先来看看有哪些因素会导致 OutOfMemoryError,其中内存泄漏是导致 OutOfMemoryError 的一个比较常见的原因,最后我们通过一个实战案例来定位内存泄漏。
内存溢出场景及方案
java.lang.OutOfMemoryError: Java heap space
JVM 无法在堆中分配对象时,会抛出这个异常,导致这个异常的原因可能有三种:
内存泄漏。Java 应用程序一直持有 Java 对象的引用,导致对象无法被 GC 回收,比如对象池和内存池中的对象无法被 GC 回收。
配置问题。有可能是我们通过 JVM 参数指定的堆大小(或者未指定的默认大小),对于应用程序来说是不够的。解决办法是通过 JVM 参数加大堆的大小。
finalize 方法的过度使用。如果我们想在 Java 类实例被 GC 之前执行一些逻辑,比如清理对象持有的资源,可以在 Java 类中定义 finalize 方法,这样 JVM GC 不会立即回收这些对象实例,而是将对象实例添加到一个叫“java.lang.ref.Finalizer.ReferenceQueue”的队列中,执行对象的 finalize 方法,之后才会回收这些对象。Finalizer 线程会和主线程竞争 CPU 资源,但由于优先级低,所以处理速度跟不上主线程创建对象的速度,因此 ReferenceQueue 队列中的对象就越来越多,最终会抛出 OutOfMemoryError。解决办法是尽量不要给 Java 类定义 finalize 方法。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入分析了Tomcat内存溢出问题,从多个角度探讨了导致JVM抛出OutOfMemoryError异常的原因,并提供了相应的解决方案。首先介绍了导致内存溢出的常见场景,包括Java heap space、GC overhead limit exceeded、Requested array size exceeds VM limit、MetaSpace等,并针对每种场景详细解释了可能的原因和解决方法。此外,还介绍了其他类型的OutOfMemoryError异常,如OutOf swap space和Unable to create native threads,并提供了相应的解决方案。通过分析不同的内存溢出场景,为读者提供了全面的原因分析和调优方案,对于解决Tomcat内存溢出问题具有一定的参考价值。 文章还通过实例演示了内存泄漏的定位实战,通过创建一个Web应用,不断地向List中添加对象来模拟内存泄漏,并使用各种工具观察GC的行为,最终通过生成Heap Dump找到泄漏点。通过这个实例,读者可以学习到如何观察GC的过程、使用GCViewer工具查看GC日志、通过jmap工具生成Heap Dump,并通过Eclipse Memory Analyzer进行内存泄漏分析。最后,文章强调了在实际工作中需要根据具体的错误信息去分析背后的原因,尤其是在Java堆内存不够时需要生成Heap Dump来分析,以及调整各种JVM参数来解决问题。 总的来说,本文内容丰富,涵盖了内存溢出的多种场景和解决方法,通过实例演示帮助读者更好地理解和应用相关技术。对于Java程序员和系统运维人员来说,本文具有很高的实用价值。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Tomcat & Jetty 》,新⼈⾸单¥68
《深入拆解 Tomcat & Jetty 》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(20)
- 最新
- 精选
- 尔冬橙老师的这门课太值了啊,可能很多人看到只是是tomcat所以没来买这门课,但是老师的课程里涉及到到了java的方方面面,真的是如获至宝。
作者回复: 谢谢夸奖😄
2019-08-16223 - 木小柒刚入职现在的公司,发现线上某个实例会不定期不提供服务,进程还在,但是不再接受请求。每次都重启就恢复,后来一直观察。线上没写权限,也没什么监控工具,就是那种突然出问题,还要临时申请写权限去机器上执行jvm的相关命令。有时候也抱怨权限这东西,就跟站着茅坑不拉屎一样搞笑,有权限的人不做,要做的人做不了。有次用eclipse的工具看了下,dubbo对象特别多,都超过spring boot的了,看了dubbo的代码,发觉居然是每次都new出Reference来的,没有用注解,没有交给spring接管。交给容器后,后来也出现过服务不可用。一次偶然的机会,排查另一个问题时发现mybatis数据库异常,分析日志得知一个sql查询足足执行了30多分钟,看了sql语句,where条件触发了全表超大量数据扫描,然后服务就撑差不多半小时,异常之前服务是正常提供的,直到oom时僵尸。因为订单表订单号是拆单,父订单的父订单号自然为0,有一些老订单数据不符合规范,导致查询了订单号为0的sql。本地模拟果不其然,执行半个小时后就oom,服务不可用。oom是标准输出,日志并无该提示,导致一直未能看到。就加了一个if订单号不为0就解决了,你说这代码写的,找谁说理去。这个问题足足留意了差不多2个月,才找到是这么个原因,居然骂人都没脾气的问题。2019-08-07228
- 雨下不停在极客时间买了很多课,不得不说这门课是最喜欢的一门,有幸参与,感谢老师!2020-04-098
- 沙金谢谢老师,我这一年就遇到过两次,旁边的同事干的。。 第一次是直接查询1000个对象放在list里面,导致GC overhead limit exceeded,我也是百度搜了才知道 第二次是还是他们干的,mybatis-plus有个in操作,如果里面没有数据,默认没有条件,但sql仍然会执行,不会报错,这下就糟糕了,把全表都查出来了,最后是Java heap space 还好他没有用在delete中。。。2020-06-063
- QQ怪之前在使用es的时候想用线程池来优化频繁获取连接造成的资源浪费,但因为自己粗心,使用的过程中错误的操作获取连接都去new线程池,而不是从线程池获取线程,导致内存老是到顶,那次内存泄露还是自己的基本功不扎实导致的,最后也是通过一些jvm工具找到了问题,当时画了不少时间在上面,挺感慨的2019-08-063
- yang赞 自己手还是比较生 了解到的知识面比较窄 还是要多记 多理解 多联系 无奈平时的增删改查太多了2019-08-063
- Geek_8c4282老师,如果在线上jmap生成堆栈会影响线上服务器性能吧,服务器会卡顿吧2019-12-1922
- neohopeYGC 表示 Minor GC 的总时间,YGCT 表示 Minor GC 的次数。这两个是写反了吗?2019-08-0622
- James还好看了这模块的文章,之前出现过,无套路处理事情就是在做无用功。2021-03-251
- sun留白Heap Dump 是 Java进程所使用的内存情况在某一时间的一次快照。以文件的形式持久化到磁盘中。 Heap Dump的格式有很多种,而且不同的格式包含的信息也可能不一样。但总的来说,Heap Dump一般都包含了一个堆中的Java Objects, Class等基本信息。同时,当你在执行一个转储操作时,往往会触发一次GC,所以你转储得到的文件里包含的信息通常是有效的内容(包含比较少,或没有垃圾对象了) 。2020-02-121
收起评论