频繁的垃圾收集java web应用程序

时间:2010-08-24 22:05:15

标签: java garbage-collection

我有一个Web应用程序,它根据用户请求将java bean序列化为xml或json。

当我对它施加一点负荷时,我正面临着一个弯曲的问题,它会快速使用所有已分配的内存,并达到最大容量。然后,我每20-40秒观察一次完整的GC工作。

看起来不像是内存泄漏问题......但我不太确定如何解决这个问题?

序列化为xml / json的bean引用了其他bean以及其他bean。我使用json-lib和jaxb来序列化bean。

yourkit memory profiler告诉我char []是消耗最多内存的活动对象......

任何见解都表示赞赏。

9 个答案:

答案 0 :(得分:1)

有两种可能性:你有内存泄漏,或者你的webapp只会产生大量垃圾。

  • 判断你是否有内存泄漏的蛮力方法是运行它很长一段时间,看看它是否会因为OOME而崩溃。或者打开GC日志记录,看看垃圾收集后的平均空间是否会随着时间的推移不断上升。

  • 无论是否有内存泄漏,您都可以通过增加最大堆大小来提高性能(减少GC时间百分比)。你的webapp看到很多完整的GC这一事实告诉我它需要更多的堆。 (如果您有内存泄漏,这只是一个绑定解决方案。)

  • 如果事实证明您没有遭受内存泄漏,那么您应该看看为什么您的应用程序产生了如此多的垃圾。它可能取决于您进行XML和JSON序列化的方式。

答案 1 :(得分:1)

为什么你认为你有问题? GC是一种自然而正常的事情。我们的客户每秒都会使用GC(持续时间不到100毫秒),只要内存不断回收就可以了。

每隔20-40秒进行一次GC测量不是问题IMO - 只要不占20-40秒的大部分时间。大多数主要商用JVM旨在将GC保持在5-10%的时间范围内(因此20-40秒内的1-4秒)。以GC日志的形式发布更多数据可能会有所帮助,我还建议GCMV之类的工具可以帮助您查看并获取有关GC配置文件外观的建议。

答案 2 :(得分:0)

如果没有更多的信息 - 代码和GC日志 - 就无法对此进行诊断 - 但我的猜测是你用大字符串读取数据,然后使用substring()删除少量数据。当你这样做时,子串字符串使用与父字符串相同的基础字符数组,并且只要它处于活动状态,就会将该数组保留在内存中。这意味着代码如下:

String big = a string of one million characters;
String small = big.substring(0, 1);
big = null;

仍会将大字符串的字符数据保存在内存中。如果是这种情况,那么你可以通过强制小字符串通过构造新实例来使用新的,更小的字符数组来解决它:

small = new String(small);

但就像我说的,这只是猜测。

答案 3 :(得分:0)

我不确定您的代码中有多少以及您使用的工具可能有多少,但有一些关键的事情需要注意。

最糟糕的情况之一是你经常在循环中添加字符串。一个简单的“你好”+“世界”根本不是问题,它实际上非常聪明,但如果你在循环中这样做,它将不断重新分配字符串。尽可能使用StringBuilder。

有一些Java的分析器可以快速指出分配发生的位置。在您的Java应用程序运行时,只需使用分析器一段时间就可以搞错,除非问题出在您的库中,否则您可能无法将GC降低到几乎没有 - 即使这样,您也可以找到解决问题的方法。

您分配然后快速免费的事情在GC阶段不需要时间 - it's pretty much free。确保你没有比你需要的更长时间保持字符串。在从请求处理程序返回之前,将它们带入,处理它们并返回到先前的状态。

答案 4 :(得分:0)

您应该附加您的套件和记录分配(例如,每10次分配;包括所有大型分配)。他们有一个逐步指导诊断过多的gc: http://www.yourkit.com/docs/90/help/excessive_gc.jsp

答案 5 :(得分:0)

对我来说,听起来你正试图通过某些编码器序列化一个递归对象,而这个编码器并没有为它做好准备。 (或至少:非常深/几乎递归)

答案 6 :(得分:0)

Java的原生XML API实际上是“嘈杂的”,并且在资源方面通常是浪费的,这意味着如果您的请求和XML / JSON生成周期很短,那么GC将有很多需要清理的地方。

我已经调试了一个非常类似的案例,并且发现了这个困难的方法,只有这样我才能在没有重大重构的情况下至少在某种程度上改善这种情况,而是隐含地使用适当的VM标志调用GC实际上将System.gc();转换为非操作电话也许 - 操作电话

答案 7 :(得分:0)

我首先检查正在运行的应用程序,看看堆上创建了什么。 HPROF可以为您收集此信息,然后您可以使用HAT进行分析。

答案 8 :(得分:0)

要调试内存分配问题,可以在命令行中使用InMemProfiler。可以跟踪收集的对象分配,并且可以基于收集的生存期将收集的对象拆分成桶。

在跟踪模式下,此工具可用于identify the source of memory allocations

相关问题