内存泄漏,对象数量或大小没有增长

2022-09-01 23:47:45

在 IBM iSeries 系统上,我正在运行一个 Java 程序 - 一个带有 Web 服务器组件的应用程序服务器,全部由内部开发。在 32 位或 64 位 J9 JVM(IBM 技术 Java)上运行时,我有内存泄漏的症状。

请注意,在iSeries经典JVM,多个Sun / Oracle JVM和Linux JVM上运行此软件没有任何问题。哎呀,当我在我的网站上工作时,我经常在我妻子的入门级笔记本电脑上一次运行相同的软件数周 - 我可以向你保证,如果它泄漏内存,它会注意到那件事。

如果我只是让一个普通的系统空闲运行,没有配置任何应用程序(基本上只是消息传递系统和Web服务器),堆就会继续缓慢增长,导致随着时间的推移分配更多的内存,每个GC周期都不会完全收集到以前的水平。对于没有问题的JVM,模式完全相同,除了在那些JVM上,GC扫描总是将堆减少到其以前的GC级别。

enter image description here

但是,如果我在稳定后在启动时拉取 JVM 系统转储,并在分配的堆显著增长后拉取后续转储,则差异比较表明,运行一周后可访问的对象并不比启动时更多。最近的一个,一周后显示加载了6个额外的类,一些对象显然与此相关。对所有活体的彻底审查表明,没有什么让我意想不到的。

我尝试了针对吞吐量优化和代并发垃圾回收器。

因此,根据作业的堆大小,我们似乎正在泄漏,而根据堆转储,没有任何泄漏。

没有调用JNI方法(除了作为核心JVM的一部分运行的本机代码),而且肯定是堆积在增长 - 我可以在IBM WRKJVMJOB信息中清楚地看到这一点,并在我的控制台日志文件中使用JMX bean进行报告。

到目前为止,我无法使用JMX工具(如JVisualVM)连接到活动JVM,因为尽管侦听套接字是在正确配置时创建的,但连接被拒绝,显然是在协议级别(TCP / IP堆栈显示接受的连接,但JVM将其反弹)。

我很困惑,不知道下一步该去哪里。

编辑:只是为了澄清;这些结果都是使用未插入的JVM,因为我无法获得JMX访问此JVM(我们正在与IBM合作)。

EDIT 2011-11-16 19:27:我能够在1823个GC周期中提取GC活动报告,其中包括软/弱/幻影参考计数的特定计数;这些数字没有失控增长的迹象。然而,小对象固定空间有显著增长(大对象固定空间是空的)。它从900万增长到3600万。


答案 1

在我的程序中消除了一些粗心的内存浪费(尽管没有任何泄漏),并更好地针对我们的工作负载调整了GC,我将失控的内存使用量降低到可以容忍的水平。

但是,在此过程中,我已经证明AS/400(又名iSeries,Systemi,i5等)上使用的IBM J9 JVM具有1336字节/分钟的泄漏,总计2 MB /天。我可以通过各种程序从“单行”测试程序一直到我们的应用程序服务器来观察这种泄漏。

一行测试程序是这样的:

public class ZMemoryLeak2
extends Object
{

static public synchronized void main(String... args) {
    try { ZMemoryLeak2.class.wait(0); } catch(InterruptedException thr) { System.exit(0); }
    }

}

一个单独的测试程序除了通过JMX API监控内存使用情况之外什么也没做,它最终表明1336 B以1分钟的间隔泄漏,永远不会被回收(好吧,运行2周后没有回收)。OP注意:实际上,JVM的每个变体的数量都略有不同。

2012-04-02 更新:几周前,IBM 认为这是一个错误;它实际上是在去年年中左右在Java 5中发现并修补的,Java 6的补丁预计将在下周或两周内推出。


答案 2

一种可能的解释是,您正在看到使用或类似方式实现的缓存中对象的构建。场景如下:WeakReference

  • 您在图中看到的 GC 循环是新空间的集合,不会导致引用中断。因此,缓存继续增长并使用更多的堆空间。

  • 拍摄快照时,这会导致运行一个完整的 GC,该 GC(可能)会中断引用,并释放缓存的对象。

(注意“也许”。我不确定这个解释是否成立...)


另一种可能的解释是,您的应用程序具有相同数量的对象,但其中一些对象更大。例如,您可能有一个具有某种基元类型的数组,您不断以更大的大小重新分配这些数组。或者一个StringBuilder / StringBuffer不断增长。或者(在某些情况下)一个不断增长的ArrayList或类似的数组列表。


你知道,你可能在这里追逐一个幻影。可能是系统转储说的是实话,根本没有存储泄漏。您可以通过将堆大小减小到实际内存泄漏可能会相对快速地引发OOME的程度来测试该理论。如果我不能以这种方式挑衅OOME,我倾向于把它写成一个有趣的好奇心......并转到一个真正的问题。


推荐