能否在序列化对象到流的同时,读取该流完成反序列化以克隆对象?
问题解答
1. 是否存在边序列化边反序列化的克隆方案?
不存在能同时将对象序列化到流并从该流反序列化出克隆对象的通用JSON序列化器。核心原因是JSON基于完整结构解析,反序列化必须读取完整的JSON文档才能重建有效对象——序列化未完成时,流内数据不完整,无法完成反序列化逻辑。
你提到的「先序列化到流、刷新写入器并重置指针」是当前最可行的替代方案,虽然是先写后读的顺序操作,但已经能实现避免分配超大JSON字符串的目标。
2. 内存中已有大对象,这种操作是否有意义?
有明确意义,核心价值在于避免中间大字符串对象进入大对象堆(LOH):
- 源对象本身确实占用内存,但如果直接序列化到字符串,1-2MB的对象会生成2-4MB的UTF-16编码JSON字符串,必然进入LOH;LOH回收效率低,易造成内存碎片。
- 改用流序列化时,操作的是UTF-8编码字节流,内存占用仅为对应字符串的一半,且可通过池化缓冲区等方式进一步降低LOH分配压力。即使使用普通
MemoryStream,也能避免额外的字符串对象分配,减少LOH的内存碎片问题。
3. 具体实现示例
Newtonsoft.Json 方案
public static T CloneWithStream<T>(T source) where T : class { using var stream = new MemoryStream(); var serializer = new JsonSerializer(); // 序列化到流 using var writer = new JsonTextWriter(new StreamWriter(stream)); serializer.Serialize(writer, source); writer.Flush(); // 重置流指针到起始位置 stream.Position = 0; // 反序列化克隆对象 using var reader = new JsonTextReader(new StreamReader(stream)); return serializer.Deserialize<T>(reader); }
System.Text.Json 方案
public static T CloneWithStream<T>(T source) { using var stream = new MemoryStream(); JsonSerializer.Serialize(stream, source); stream.Position = 0; return JsonSerializer.Deserialize<T>(stream); }
补充优化建议
若想进一步降低内存开销,可尝试:
- 使用池化内存流(基于
ArrayPool<byte>自定义流实现),避免频繁创建大字节数组。 - 替换为二进制序列化器(如Protobuf-net),二进制格式的内存占用远低于JSON,序列化/反序列化速度更快,但需为对象配置契约或标记特性,兼容性略逊于JSON。
内容的提问来源于stack exchange,提问作者dropsoid
相关产品推荐
相关产品推荐

