【问题标题】:Spring Boot Jackson taking large amount of memorySpring Boot Jackson 占用大量内存
【发布时间】:2020-01-15 20:06:46
【问题描述】:

Spring Boot 需要大约 3 GB 内存来将 300 mb 有效负载转换为对象

我发送到 Spring Boot Web 应用程序的 POST 请求负载为 300 mb。但是 SpringBoot 应用程序 esp Jackson 解析器正在讨论 3gb 的内存来将请求映射到其相应的对象。

由于这个问题,我直接读取流,并且我编写了自定义解析器来解析有效负载并将其映射到对象。

JSON形式的payload如下:

{"a": "some value", "b": "this value is around 300 mb string"}

为什么 Springboot Jackson 解析器占用 3 GB 内存来将 JSON 有效负载映射到对象?我没有编写任何自定义代码,我相信 SpringBoot 内部使用 Jackson 将 JSON 映射到 Object。

SpringBoot 或 Jackson 解析器是否适合解析 300 mb 的负载?

注意:我的 JSON 负载中只有一个元素约为 300 mb。

【问题讨论】:

    标签: java jackson spring-data-jpa


    【解决方案1】:

    假设 JSON 是大多数 ASCII 字符,那么您的有效负载都是 1 字节字符。 Java 字符串是 UTF-16 编码的,所以每个字符是 2 个字节。

    这意味着您的 300 mb 有效负载是内存中的 600 Mb char[]

    由于有效负载主要是 JSON 字符串文字,因此需要提取该文字,即复制。由于大小未知,它很可能被复制到StringBuilder 中。 StringBuilder 将有一个 600 Mb char[],然后从中创建一个字符串,即另一个 600 Mb char[]

    因此,简单地提取b 字段的字符串值将消耗3 倍600 Mb。即 1.8 Gb 的内存,你甚至还没有开始为你的对象分配内存。

    当然,StringBuilder 在您开始之前有资格进行 GC,但在开始创建 POJO 之前您仍然消耗了 1.2 Gb 的内存。

    【讨论】:

    • 很好的解释@Andreas
    • 谢谢。在查看堆转储后,我们得出了相同的结论。我的自定义实现是这样的,因为我们知道有效负载的内容长度,所以我不需要StringBuilder,我可以将 600 mb 字符数组复制到字符串。所以在这里我只使用 1200 mb。我的问题是为什么杰克逊解析器占用更多内存?您是否建议任何其他替代方法来处理这个巨大的有效负载?
    • @bigdata 你怎么可能不需要StringBuilder?您不知道完整字符串的长度,除非您保证 只使用 ASCII 字符。你不知道b 字符串的长度,因为你不知道转义了多少个字符。
    • @Andreas 将 b 注释为 clob 数据类型使 jpa 流而不是将字符串加载到内存中。?
    猜你喜欢
    • 1970-01-01
    • 2014-05-11
    • 2011-02-27
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多