使用Java中的Jackson从ObjectNode创建String的速度很慢

时间:2015-07-20 11:01:06

标签: java json performance jackson

我从String节点创建JSON时遇到问题。

目前我正在通过node.toString()方法进行此操作。但有时这需要7-8秒来创建加权15MB-18MB的JSON字符串。

我也尝试使用mapper.writeValueAsString(node))方法。但它显示了一些额外的测试时间。这很难检查问题,因为它也很难重现。

我目前只使用ObjectNode(不是TextNodeBooleanNode等)是否会对此产生影响?或者有没有更好的方法将JSONNode转换为String

示例代码:     JsonNodeFactory nodeFactory = JsonNodeFactory.instance;

ObjectNode  node  = nodeFactory.objectNode();
node.put("fnm", "Namal");
node.put("lnm", "Fernando");
node.put("age", 30);

for (int i = 0; i < 10000; i++) {

    ObjectNode  order  = nodeFactory.objectNode();
    order.put("id", (i+1000)+"");
    order.put("nm", "ORD"+(i+1000));
    order.put("ref", "RF-"+i);

    node.put("order"+i, order);

}

long smili  = System.currentTimeMillis();
System.out.println("main().Node : " + node.toString());
System.out.println("main().TIMING 1 : " + (System.currentTimeMillis() - smili) / 1000.0);;

long smili2 = System.currentTimeMillis();
ObjectMapper mapper = new ObjectMapper();

System.out.println("main().Node : " + mapper.writeValueAsString(node));
System.out.println("main().TIMING 2 : " + (System.currentTimeMillis() - smili2) / 1000.0);;

1 个答案:

答案 0 :(得分:2)

首先要做的事情:JsonNode.toString()不应该用于序列化。它对于简单的故障排除很有用,但由于它无法访问上下文配置,因此它不一定会生成有效的JSON。这是设计的。 相反,您应该使用ObjectMapperObjectWriter来序列化它;这将使用映射器具有的精确配置和设置(或映射器创建的编写器)生成有效的JSON。

现在:您的时间比较存在缺陷,因为您只使用ObjectMapper进行一次通话。前N次呼叫有开销;部分原因是ObjectMapper初始化,部分原因是JVM预热(动态JIT编译器运行优化等)。为了获得更多可用的结果,您需要多次调用方法,理想情况下让它运行几秒钟。

但除此之外,常见的问题是忘记拥有足够的堆空间。 在Java中,字符串要求内存至少相当于字符串长度的2倍(每个char需要2个字节)。但这只是结果的大小;在序列化期间,还需要使用大致可比较的量的临时缓冲区。 但是,在磁盘上,UTF-8编码通常每个字符只使用1个字节(对于ASCII字符)。

因此,假设您看到一个15mB的文件,它可以在处理过程中使用60 MB的内存。如果您的堆大小设置为较小(例如,在许多情况下默认为64兆),则会导致非常繁重的垃圾收集处理。解决方案是增加堆大小。 或者,除非您确实需要String,否则:

  1. 直接写入文件:如果结果进入String或网络连接
  2. ,则使用中间File是反模式
  3. 如果你确实需要中间形式,序列化为byte[]:这只需要与文件相同的内存量(因为它在内存中是UTF-8编码,而不是包裹{{1} }