JVM中驻留内存大小的增加是否表明存在内存泄漏



我正在使用以下命令行选项启动JBoss 4.2服务器实例:

-Xms8192m -Xms8192m -XX:+DisableExplicitGC -XX:MaxPermSize=512m

我没有收到一个OutOfMemoryException,但我不希望内存使用增加,如果事情被GC作为他们的引用死亡。常驻内存使用量(用top测量)从4.2G开始,在接下来的几天到一周内稳步增加,直到达到8.4G。我仍然没有收到异常。我担心的是,在重要的活动期间(JBoss消息处理> 10k消息/秒),每6-10秒就会出现约100-700ms的处理延迟。这似乎也与驻留内存使用量的增加有关。

我将打开额外的命令行参数:

verbosegc - xx: + PrintGCDetails

但是,我想知道如果这似乎是一个垃圾收集问题,或内存泄漏?几个星期以来,我一直试图追踪潜在的内存泄漏,并发现了一些我认为肯定会修复它的XML处理,但这是一个死胡同。无论是否存在泄漏(特别是禁用了显式GC),驻留内存使用量是否会上升到满足Xmx的值?如果确实不是泄漏,是否有其他一些垃圾收集参数可能会有所帮助(例如修改垃圾收集器类型、存活比率或暂停目标)?

我知道100-700ms的延迟看起来并不多,但它有可能在这个应用程序中产生显著的差异。事先感谢您提供的任何帮助/建议。

Java中"泄漏"的定义与C/c++中"泄漏"的定义有本质上的不同。在C/c++中,当您mallocnew一块存储并且从未随后freedelete它时,您会得到一个"泄漏"。

但是在Java中,当然,你永远不会删除任何东西,而是让GC找到不再引用的东西并释放它。

然而,可能发生的情况是,一些复杂的数据结构被构建起来,然后再构建一些,然后再构建更多,有时是无意的。

最明显的情况是类似StringBuffer的东西,它用于积累日志信息,从不写入/清空。但是你也可以在你的应用程序中有一个(故意的)长寿命的结构,你碰巧"停放"了一些(假定的)短寿命的对象,但是在你处理完这个对象之后,却没有null指向这个"短寿命"对象的指针,导致它实际上变成了不朽的。这些事情有些是显而易见的,有些则需要大量的调查才能弄清楚。

但是在大型服务器中,即使没有这样的泄漏,您也倾向于在一段时间内相当稳定地积累"东西"。例如,如果调用给定的应用程序,可能会导致创建一些对象(或者只是加载类,它们间接创建对象),并且这些对象可能"挂起"直到下一次调用应用程序。像网页缓存之类的东西会被填满。如果使用了类似JSP的东西,则将为其创建对象并"缓存"以供以后使用。

但是这种"物质"的积累应该观察到一个渐近的行为,随着时间的推移慢慢接近某个稳态值。如果它在稳定状态下继续上升,那么你可能确实有"泄漏"。

关于GC行为,在繁忙的服务器上每隔几秒钟运行一次GC是很正常的。你可以通过调整参数来"平衡"不同的GC"层",但这样做有点像巫术。通常,服务器上糟糕的GC性能仅仅是因为GC实现没有为服务器设计好——繁忙服务器上的GC需要能够以大部分并发方式运行,而大多数GC实现在这方面做得都不太好。

我没有收到一个OutOfMemoryException,但我不希望如果将内容作为引用进行GC处理,则内存使用量会增加死。

这并不一定正确。对象可以放置在堆的保留期内存中。如果对象被引用的时间超过"短时间",就会发生这种情况。一旦进入保留期,它通常不会被垃圾收集,直到达到最大堆。因此,仅仅因为堆内存使用没有减少并不意味着您有泄漏。

正常的内存配置文件(堆使用与时间)看起来像锯齿形-内存使用缓慢增加,直到达到某个阈值(通常是最大堆),然后由于GC而减少,然后又缓慢增加。

我要添加的唯一一件事是尝试将分析器连接到您的应用程序,并查看内存使用行为。我已经成功地用jProfiler和YourKit分析了Weblogic A.S.的实例,虽然我还没有尝试过用JBoss,应该相当容易。

你能在测试环境中复制这种行为吗(因为分析器对性能有点重,只有在你绝望的时候才在生产环境中做)?如果这样做,就可以看到GC是否只在达到XMX阈值时才被调用(这并不意味着有任何问题),并且可以显式地调用GC来查看它的行为。如果即使使用GC调用,内存也会不断增加,这可能表明存在问题。

一个好的分析器可以告诉你哪些对象在数量上增长得更快,如果你确实有"泄漏",这可以极大地帮助你。

最新更新