Java树形Node对象转JSON时OOM异常的解决方案咨询
解决树形结构转JSON的OOM问题方案
核心思路是避免在内存中构建完整JSON对象,采用流式API逐节点写入,无论树的规模多大,内存仅需存储当前遍历的节点。
1. Gson流式写入方案(适配你已使用的Gson)
直接使用Gson底层的JsonWriter配合深度优先遍历,边遍历树边写入JSON,全程内存占用极低:
代码实现
import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.io.Writer; import java.util.List; public class NodeJsonSerializer { public void serialize(Node root, Writer writer) throws IOException { JsonWriter jsonWriter = new JsonWriter(writer); // 可选:开启缩进格式化JSON,不需要可删除 jsonWriter.setIndent(" "); serializeNode(root, jsonWriter); jsonWriter.close(); } private void serializeNode(Node node, JsonWriter jsonWriter) throws IOException { jsonWriter.beginObject(); // 写入name字段 jsonWriter.name("name").value(node.name); // 写入children数组 jsonWriter.name("children"); jsonWriter.beginArray(); if (node.children != null) { for (Node child : node.children) { serializeNode(child, jsonWriter); } } jsonWriter.endArray(); // 写入values数组 jsonWriter.name("values"); jsonWriter.beginArray(); if (node.values != null) { for (Object value : node.values) { // Gson自动适配基本类型、字符串等对象的写入 jsonWriter.value(value); } } jsonWriter.endArray(); jsonWriter.endObject(); } }
使用方式
直接传入输出流(如文件流、网络流),无需在内存中缓存完整JSON:
// 示例:写入到本地文件 try (FileWriter writer = new FileWriter("output.json")) { new NodeJsonSerializer().serialize(rootNode, writer); } catch (IOException e) { e.printStackTrace(); }
2. 额外排查优化点
如果流式方案仍出现OOM,检查以下问题:
- 循环引用:树中是否存在父节点引用子节点、子节点反向引用父节点的情况?可通过
Set记录已访问节点的唯一标识,避免无限遍历。 - 大对象存储:
values列表中的对象是否为大字节数组、超大字符串?这类对象可单独处理(如写入磁盘后在JSON中存路径),若必须存入JSON,流式写入仍能支撑,但需确保Writer的缓冲区不要过大。 - JVM堆内存配置:可临时调整堆内存参数(如
-Xmx4g)验证,但流式方案才是根本解决方式。
3. 替代方案:Jackson流式API
若愿意更换JSON库,Jackson的JsonGenerator同样支持流式写入,逻辑与Gson一致:
import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import java.io.IOException; import java.io.Writer; public class NodeJacksonSerializer { public void serialize(Node root, Writer writer) throws IOException { JsonFactory factory = new JsonFactory(); try (JsonGenerator gen = factory.createGenerator(writer)) { gen.useDefaultPrettyPrinter(); // 可选格式化 serializeNode(root, gen); } } private void serializeNode(Node node, JsonGenerator gen) throws IOException { gen.writeStartObject(); gen.writeStringField("name", node.name); gen.writeFieldName("children"); gen.writeStartArray(); if (node.children != null) { for (Node child : node.children) { serializeNode(child, gen); } } gen.writeEndArray(); gen.writeFieldName("values"); gen.writeStartArray(); if (node.values != null) { for (Object value : node.values) { gen.writeObject(value); } } gen.writeEndArray(); gen.writeEndObject(); } }
内容的提问来源于stack exchange,提问作者DEV
相关产品推荐
相关产品推荐

