java - 泄漏的 Java 库慢慢占用所有内存,没有抛出 OutOfMemoryException,解决方法?

标签 java memory-leaks jvm batch-processing odf

我正在使用 java odftoolkit 库 (simple-odf-0.6.6) 进行 odf 文档操作。我们在循环中迭代所有文档:

TextDocument textdoc = TextDocument.loadDocument(odtFileName);
.
changing content of document
.
textdoc.save(anotherOdtFileName);
textdoc.close();
//then all resources/streams are correctly closed, checked that many times by my colleagues :)

当我们迭代数千个文档时,java 应用程序会慢慢占用所有内存,然后由于 GC 试图释放一些内存,一切都会变慢。我们没有得到 OutOfMemoryException。

我尝试调整 JVM 内存大小和 GC 选项 ( http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html ) - 应用程序等待几分钟,但随后所有内存再次消耗。

这是应用程序达到所有可用内存时从转储中获取的样本:

652.147: [Full GC 652.147: [Tenured: 454655K->454655K(454656K), 2.2387530 secs] 659263K->659216K(659264K), [Perm : 41836K->41836K(42112K)], 2.2388570 secs] [Times: user=2.25 sys=0.00, real=2.23 secs] 
654.387: [Full GC 654.387: [Tenured: 454656K->454656K(454656K), 2.2661510 secs] 659263K->659223K(659264K), [Perm : 41836K->41836K(42112K)], 2.2663190 secs] [Times: user=2.26 sys=0.00, real=2.26 secs] 
656.654: [Full GC 656.654: [Tenured: 454656K->454656K(454656K), 2.4117680 secs] 659263K->659229K(659264K), [Perm : 41836K->41836K(42112K)], 2.4118970 secs] [Times: user=2.41 sys=0.00, real=2.41 secs]

如您所见,仅释放了几 kB,GC 速度非常慢(超过 2 秒)。

这个jmap直方图显示了最大的消费者:

 num     #instances         #bytes  class name
----------------------------------------------
   1:       2535190       99077856  [C
   2:       2529791       60714984  java.lang.String
   3:         21085       27956544  [B
   4:        389820       16181680  [Ljava.lang.Object;
   5:        147111       13373896  [Ljava.util.HashMap$Entry;
   6:        108426       13180496  <constMethodKlass>
   7:        518834       12452016  java.util.HashMap$Entry
   8:        108426        9547136  <methodKlass>
   9:        321713        7721112  java.util.Vector
  10:        306308        7351392  org.apache.xerces.dom.AttributeMap
  11:        144353        6928944  java.util.HashMap
  12:         10230        5879960  <constantPoolKlass>
  13:         10230        5089344  <instanceKlassKlass>
  14:        114065        4562600  org.odftoolkit.odfdom.dom.attribute.text.TextStyleNameAttribute
  15:         58248        4193856  org.odftoolkit.odfdom.incubator.doc.text.OdfTextParagraph
  16:         90041        3601640  org.odftoolkit.odfdom.pkg.OdfAlienAttribute
  17:         36437        3459000  [I
  18:         48609        3110976  java.util.zip.ZipEntry
  19:          7454        2939616  <constantPoolCacheKlass>
  20:         36491        2627352  org.odftoolkit.odfdom.incubator.doc.style.OdfStyle
  21:         36399        2620728  org.odftoolkit.odfdom.incubator.doc.text.OdfTextSpan
  22:         58397        2335880  org.odftoolkit.odfdom.dom.attribute.style.StyleNameAttribute
  23:         65517        2096544  org.apache.xerces.dom.TextImpl
  24:         24270        1747440  org.odftoolkit.odfdom.incubator.doc.text.OdfTextListLevelStyleBullet
  25:         36511        1460440  org.odftoolkit.odfdom.dom.attribute.style.StyleFamilyAttribute
  26:         24335        1362760  org.odftoolkit.odfdom.dom.element.style.StyleParagraphPropertiesElement
  27:         24320        1361920  org.odftoolkit.odfdom.dom.element.style.StyleListLevelPropertiesElement
  28:         24320        1361920  org.odftoolkit.odfdom.dom.element.style.StyleListLevelLabelAlignmentElement
  29:         10933        1316952  java.lang.Class
  30:         29175        1167000  org.odftoolkit.odfdom.dom.attribute.style.StyleParentStyleNameAttribute
  31:         19464        1089984  org.odftoolkit.odfdom.dom.element.style.StyleFontFaceElement
  32:         68003        1088048  java.lang.Integer
  33:          3531        1082640  <methodDataKlass>
  34:         26757        1070280  org.odftoolkit.odfdom.dom.attribute.fo.FoMarginLeftAttribute
  35:         26752        1070080  org.odftoolkit.odfdom.dom.attribute.fo.FoTextIndentAttribute
  36:         24330         973200  org.odftoolkit.odfdom.dom.attribute.style.StyleWritingModeAttribute
  32:         68003        1088048  java.lang.Integer
  33:          3531        1082640  <methodDataKlass>
  34:         26757        1070280  org.odftoolkit.odfdom.dom.attribute.fo.FoMarginLeftAttribute
  35:         26752        1070080  org.odftoolkit.odfdom.dom.attribute.fo.FoTextIndentAttribute
  36:         24330         973200  org.odftoolkit.odfdom.dom.attribute.style.StyleWritingModeAttribute
  37:         24320         972800  org.odftoolkit.odfdom.dom.attribute.text.TextListLevelPositionAndSpaceModeAttribute
  38:         24320         972800  org.odftoolkit.odfdom.dom.attribute.text.TextLevelAttribute
  39:         24320         972800  org.odftoolkit.odfdom.dom.attribute.text.TextListTabStopPositionAttribute
  40:         24320         972800  org.odftoolkit.odfdom.dom.attribute.text.TextLabelFollowedByAttribute
  41:         24315         972600  org.odftoolkit.odfdom.dom.attribute.fo.FoLineHeightAttribute
  42:         24270         970800  org.odftoolkit.odfdom.dom.attribute.text.TextBulletCharAttribute
  43:         17064         955584  org.odftoolkit.odfdom.dom.element.style.StyleTextPropertiesElement
  44:         38372         920928  java.util.ArrayList
  45:         12135         873720  org.odftoolkit.odfdom.dom.element.text.TextAElement

如你所见,内存中有很多 odftoolkit 相关的类。

有什么有效的方法可以解决这个问题吗?如果有可能在运行时从我们的应用程序卸载 odftoolkit 并再次加载它以清除内存中的所有对象(显然它链接在一起,GC 不能做任何有用的事情),那就太好了。

我们也在考虑将关键代码作为较小的文档组的单独进程运行,但这并不能解决问题的原因。

最佳答案

您很可能存在存储泄漏,要么是由于库本身存在问题,要么是因为您没有正确使用它。我们需要一个正确构造的 minimal reproducible example知道哪个。

您看到的糟糕性能是典型的“GC 死亡螺旋”行为,应用程序运行 GC 的时间越来越多,回收的内存越来越少。在 GC 反复运行几分钟或几小时后,它很可能最终导致 OOME。

处理死亡螺旋的方法是使用 UseGCOverheadLimit JVM 开关来限制在垃圾收集上花费的时间。如果 GC 占用的时间超过指定比例,JVM 会主动抛出 OOME 消息“超出 GC 开销限制”。这是一件好事……一般来说。

然后您尝试追踪存储泄漏。


许多资源都涵盖了追踪 Java 存储泄漏。对于初学者,这里是关于该主题的 StackOverflow 问答:

基本思想是使用一种工具(有很多)来识别正在泄漏的对象,然后通过对象引用链返回以找出它们可以访问的原因什么时候不应该。

关于java - 泄漏的 Java 库慢慢占用所有内存,没有抛出 OutOfMemoryException,解决方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16807576/

相关文章:

java - 沙盒 JVM 以保护服务器免受不受信任的来源

php - 我的 PHP 应用程序内存泄漏(使用 Codeigniter 框架构建)

ios5 - 如何在iphone sdk中的XCODE中检查崩溃日志

javascript - Wicket:访问 FileUploadFile 选定的文件

java - java中c++的pwd.h lib的等价物

objective-c - 我打算如何释放从类方法返回的数组?

java - 如何解读Java G1 GC暂停时间原因

java - JVM DNS 缓存和 DNS 循环

java - 复合主键和外键 jpa

java - Java中BASE64类的编解码算法效率如何?