Objectmapper writeValueAsString 抛出 OOM 异常

Posted

技术标签:

【中文标题】Objectmapper writeValueAsString 抛出 OOM 异常【英文标题】:Objectmapper writeValueAsString throwing OOM Exception 【发布时间】:2020-04-24 15:43:33 【问题描述】:

我反复使用 Jackson 的 writeValueAsString 方法将一个对象转换为一个字符串,就像重复了几千次一样。 JSON 的大小约为 1KB。但过了一会儿,我的程序退出并抛出 OOM 异常。以下是堆栈跟踪:

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.OutOfMemoryError: Java heap space
        at com.fasterxml.jackson.core.util.TextBuffer.carr(TextBuffer.java:864)
        at com.fasterxml.jackson.core.util.TextBuffer.expand(TextBuffer.java:825)
        at com.fasterxml.jackson.core.util.TextBuffer.append(TextBuffer.java:590)
        at com.fasterxml.jackson.core.io.SegmentedStringWriter.write(SegmentedStringWriter.java:58)
        at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator._writeString2(WriterBasedJsonGenerator.java:1013)
        at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator._writeString(WriterBasedJsonGenerator.java:982)
        at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator.writeString(WriterBasedJsonGenerator.java:377)
        at com.fasterxml.jackson.databind.ser.std.StringSerializer.serialize(StringSerializer.java:41)
        at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:718)
        at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:639)
        at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
        at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3893)
        at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3207)
        at com.ad2pro.neonmigration.neondatamigration.utils.NeonMetricsProducerUtil.produceImpressions(NeonMetricsProducerUtil.java:121)
        at com.ad2pro.neonmigration.neondatamigration.scheduler.NeonScheduler.gerMetrics(NeonScheduler.java:100)
        at com.ad2pro.neonmigration.neondatamigration.NeonDataMigrationApplication.main(NeonDataMigrationApplication.java:18)
        ... 8 more
java.lang.OutOfMemoryError: Java heap space
        at javax.crypto.CipherSpi.bufferCrypt(CipherSpi.java:814)
        at javax.crypto.CipherSpi.engineUpdate(CipherSpi.java:555)
        at javax.crypto.Cipher.update(Cipher.java:2002)
        at sun.security.ssl.CipherBox.decrypt(CipherBox.java:544)
        at sun.security.ssl.EngineInputRecord.decrypt(EngineInputRecord.java:200)
        at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:974)
        at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:907)
        at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781)
        at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
        at com.amazon.support.channels.TLSSocketChannel.read(Unknown Source)
        at com.amazon.jdbc.communications.InboundMessagesThread.run(Unknown Source)
~                                       

在我的程序启动之前有 1GB 的可用内存。 objectmapper 是否持有大量内存,即使 1GB 也不足以将对象转换为字符串。任何帮助表示赞赏。

【问题讨论】:

要检查的一件事是对象是否具有导致无限循环的任何嵌套属性...这通常发生在编组具有双向关系的 JPA/Hibernate 实体时。 你需要展示你的代码,可能你有内存泄漏。 【参考方案1】:

您可以尝试通过参数 -Xmx 和 -Xms 设置 JVM 堆。例如,告诉 Jvm 占用最大 512 mb 的堆 -Xms512m。

默认最大堆大小为 64 mb,这可能对您的程序来说还不够。

【讨论】:

【参考方案2】:

这个问题有多个方面:

    如上回答中所述,增加 JVM 堆占用 512 mb。 检查是否使用objectMapper对象转换为String 每次调用时创建。 writeAsString 不应导致无休止的字符串。 使用 visualVM 并检查导致堆增加的确切原因。

【讨论】:

以上是关于Objectmapper writeValueAsString 抛出 OOM 异常的主要内容,如果未能解决你的问题,请参考以下文章

ObjectMapper - 线程安全和性能的最佳实践

无法在 Swift 中导入 ObjectMapper

ObjectMapper 和具有唯一键的数组

Alamofire,Objectmapper,Realm:嵌套对象

JAVA操作ObjectMapper类

Swift - 嵌套对象的映射 (Objectmapper)