Weblogic:内存溢出和内存泄漏问题的故障排查

在WebLogic服务器的情况下,如果这个错误是由一个execute线程抛出的,则会处理这个错误,并且会记录错误。如果连续抛出此错误,则核心运行状况监视器线程将关闭WebLogic服务器。

本机堆内存不足

=======

如果JVM不能获得更多的本机内存,它就会抛出本机内存不足(native OOM)。这通常发生在进程达到该操作系统上的进程大小限制或计算机内存和交换空间不足时。

当这种情况发生时,JVM将处理本机OOM条件,记录一条消息,指出本机内存不足或无法获取内存并退出。如果JVM或任何其他加载的模块(如libc或第三方模块)不能处理这种本地OOM情况,那么OS将向JVM发送sigabort信号,使JVM退出。通常,JVM在收到SIGABROT信号时会生成一个核心文件。

调试问题的步骤

=======

首先,确定它是java堆OOM还是本机OOM( 堆外 内存溢出

java.lang.OutOfMemoryError

java.lang.OutOfMemoryError

请注意,上面的消息转到stdout或stderr,而不是特定于应用程序的日志文件,如weblogic.log.

对于Java OOM:

收集并分析详细垃圾收集(GC)输出

=================

启用详细GC日志记录。为了有效地记录GC活动,启动时JVM中应包括以下选项:

1. 对于HotSpot: -verbose:gc 、 -XX:+PrintGCDetails 和 -XX:+PrintGCTimeStamps 。 Xloggc :也可以指定将GC详细统计信息重定向到输出文件。除了日志文件消耗的一些磁盘空间之外,基本GC的开销是空的(有关更多详细信息,请参阅Java热点VM选项)。

2. 对于JRockit: -verbose:gc , gcpause , memdbg (有关详细信息,请参阅 JRockit命令行选项 )。

确保JVM在抛出java oom之前执行以下操作

完全GC运行:

=======

执行一个完整的GC,所有不可到达的、幻象的、弱的和不可到达的对象都被移除,并且这些空间被回收。有关不同级别的对象可达性的更多详细信息,请访问: http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html ,参见“A.4.1参考对象类型”。

您可以检查是否在OOM消息之前完成了完全GC。当完成完整的GC时,会打印如下消息(格式因JVM而异:检查JVM帮助消息以了解格式)

[memory ] 7.160: GC 131072K->130052K (131072K) in 1057.359 ms

上述输出的格式如下(注意:整个模式将使用相同的格式):

[memory ] : GC K->K (K), ms

[memory ] - start time of collection (seconds since jvm start)

[memory ] - memory used by objects before collection (KB)

[memory ] - memory used by objects after collection (KB)

[memory ] - size of heap after collection (KB)

[memory ] - total time of collection (milliseconds)

但是,无法断定是否使用详细消息删除了软/弱/幻影可及对象。如果垃圾收集算法是分代算法(对于Jrockit,是gencopy或gencon,对于其他jdk,是默认算法),您还将看到详细的输出,如下所示:

[memory ] 2.414: Nursery GC 31000K->20760K (75776K), 0.469 ms

上面是托管GC(或年轻GC)循环,它将把活动对象从托管(或年轻空间)提升到旧空间。这个循环对于我们的分析并不重要。在JVM文档中可以找到关于时代算法的更多细节。

如果GC循环没有在java oom之前发生,那么它就是一个JVM错误。

完全压实:

=====

确保JVM进行了适当的压缩工作,并且内存没有碎片化,这可能会阻止分配大型对象并触发java oom错误。

Java对象需要连续的内存。如果可用的空闲内存是碎片化的,那么JVM将无法分配一个大对象,因为它可能不适合任何可用的空闲内存块。在这种情况下,JVM应该进行完全压缩,以便形成更多连续的可用内存来容纳大型对象。

压缩工作涉及将对象(数据)从java堆内存中的一个位置移动到另一个位置,并更新对这些对象的引用以指向新位置。JVM可能不会压缩所有对象,除非有需要。这是为了减少GC循环的暂停时间。

我们可以通过分析详细的gc消息来检查javaoom是否是由于碎片造成的。如果您看到类似于下面的输出,其中抛出OOM,即使有可用的java堆,那么这是由于碎片造成的。

[memory ] 8.162: GC 73043K->72989K (131072K) in 12.938 ms

[memory ] 8.172: GC 72989K->72905K (131072K) in 12.000 ms

[memory ] 8.182: GC 72905K->72580K (131072K) in 13.509 ms

java.lang.OutOfMemoryError

在上面的例子中,您可以看到指定的最大堆是128MB,当实际内存使用量只有72580K时JVM抛出了OOM,堆使用率只有55%。因此,在这种情况下,碎片的效果是抛出OOM,即使有45%的空闲堆。这是一个JVM错误或限制。您应该联系JVM供应商。

如果JVM工作正常(以上步骤中提到的所有事情),那么java oom可能是一个应用程序问题。应用程序可能会不断泄漏一些java内存,这可能会导致此问题。或者,应用程序使用更多的活动对象,需要更多的java堆内存。可以在应用程序中检查以下内容:

在应用程序中缓存——如果应用程序在内存中缓存java对象,那么我们应该确保这个缓存不会不断增长。缓存中对象的数量应该有限制。我们可以尝试减少这个限制,看看它是否减少了java堆的使用。

Java软引用也可以用于数据缓存,因为当JVM耗尽Java堆时,可以保证软访问的对象被删除。

长寿命对象-如果应用程序中有长寿命对象,那么我们可以尽可能减少对象的寿命。例如,调整HTTP会话超时将有助于更快地回收空闲会话对象。

内存泄漏:内存泄漏的一个例子是在applicationserver中使用数据库连接池时。使用连接池时,必须在 finally 块中显式关闭JDBC语句和resultset对象。这是因为对池中的连接对象调用 close() 只会将连接返回到池中以供重用,而实际上不会关闭连接和关联的语句/结果集对象。

建议遵循以下文档中建议的编码实践,以避免应用程序中的内存泄漏。

  • JDBC-关闭JDBC对象

  • JNDI-关闭上下文

  • JMS-释放对象资源

增加java堆—如果可能的话,我们还可以尝试增加java堆,看看这是否解决了问题。

变通方法—作为一种临时变通方法,当java堆使用率达到90%左右时,应用程序可以正常地重新启动。遵循此解决方法时,可以将java max堆设置为尽可能高的值,以便应用程序需要更多的时间来填充所有java堆。可以通过在java命令行中添加’ -verbosegc '标志(见上文)来监视java堆的使用情况,该标志将GC/堆使用情况信息发送到stdout或stderr。

如果上述建议都不适用于该应用程序,那么我们需要使用基于JVMPI(jvmprofiler Interface)的探查器来找出哪些对象正在占用java堆。探查器还提供了java代码中创建这些对象的位置的详细信息。本文档不包括每个探查器的详细信息。请参阅探查器文档,了解如何使用此探查器设置和启动应用程序。一般来说,基于JVMPI的探查器有很高的开销,并且大大降低了应用程序的性能。因此,不建议在生产环境中使用这些探查器。从这个站点可以浏览许多开源分析工具。

对于本机OOM问题

收集以下信息:

=======

1. 启用详细GC日志记录(见上文)以监视java堆的使用情况。这将有助于理解此应用程序的java内存需求。

应该注意的是,与应用程序实际使用的java堆无关,指定的max heap量(在java命令行中使用 -Xmx 标志)是在JVM启动时保留的,并且该保留内存不可用于任何其他用途。

在JRockit的情况下,使用 -verbose 而不是 -verbosegc ,因为这除了提供GC信息外,还提供了codegen信息。

2. 从应用程序启动到JVM耗尽本机内存,定期记录进程虚拟内存大小。这将有助于了解进程是否真正达到了该操作系统的大小限制。

对于Windows,请使用以下过程监视虚拟进程大小:

1. 在开始->运行。。。对话框中,输入“perfmon”并单击“确定”。

2. 在弹出的“性能”窗口中,单击“+”按钮(在图表上方)。

3. 在生成的“添加计数器”对话框中选择以下选项:

  • 性能对象:进程(不是默认处理器)

  • 从列表中选择计数器:虚拟字节

  • selectinstancesfromlist:选择JVM(java)实例

4. 单击“添加”,然后单击“关闭”

对于Unix或Linux,对于给定的PID,可以使用以下命令找到虚拟内存大小: ps-p-ovsz。

在Linux中,单个JVM实例中的每个java线程都显示为一个单独的进程。如果我们采用根java进程的PID就足够了。根java进程可以使用ps命令的 --forest 选项找到。例如, ps-lU–forest 将为指定用户启动的所有进程提供一个ASCII树。

计算机内存可用性

========

如果机器没有足够的RAM和交换空间,那么操作系统将无法为该进程提供更多内存,这也可能导致内存不足。确保磁盘中RAM和交换空间的总和足以满足该计算机中所有正在运行的进程的需要。

调整java堆

=======

如果java堆的使用率在max堆内,那么减少java max堆将为JVM提供更多的本机内存。这不是一个解决方案,而是一个可以尝试的解决方法。由于操作系统限制了进程大小,我们需要在java堆和本机堆之间取得平衡。

应用程序中的第三方本机模块或JNI代码

===================

检查是否正在使用任何第三方本机模块(如数据库驱动程序)。这些本机模块还可以分配本机内存,泄漏可能来自这些模块。为了缩小问题范围,您应该尝试在没有这些第三方模块的情况下再现问题。例如,可以使用纯java驱动程序而不是本机数据库驱动程序。

检查应用程序是否使用了一些JNI代码。这也可能导致本机内存泄漏,如果可能,您可以尝试在不使用JNI代码的情况下运行应用程序。

如果在上述步骤之后找不到本机内存的源,那么您需要与JVM供应商合作,以获得一个特殊的构建,该构建可以跟踪本机内存分配调用并提供有关泄漏的更多信息。

JVM内存泄露检查工具

===========

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
15707629884)]

[外链图片转存中…(img-4DPmqJja-1715707629884)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值