工作中,遇到了在Java里面序列化一颗树、然后反序列化的时候出现Stack Overflow异常的情况。整棵树的层次和在处理每层的当前对象的消耗(在栈上的消耗)累计起来造成了Stack Overflow。
晚上在家里的时候,写了个小程序,实现了Java中对一个Tree的序列化。
这个程序主要想避免层次太深的问题,所以出发点很简单,就是要改变序列化的时候的对象关系,我们要把一个层次的关系变成平的。
这个程序完成了三个版本的序列化方式。先看第一个
第一个版本在写的时候没怎么想:大概的思路是这样的,就是我们对Tree上的每个节点独立序列化,然后我们保存节点间的父子关系,序列化后的结构数据结构是这样的:
NodeCount:4bytes
//每个节点的数据
NodeId:4bytes
Node序列化后的长度:4bytes
Node序列化后的数据:1byte*序列化后的长度
Node的Child个数:4bytes
Child的NodeId:4bytes*Child个数
......表示多个节点数据
其中,NodeId是从0开始自增
完成这个版本后,大概测试了一下,序列化后的长度比Java直接序列化多了14%左右,不爽。
思考了一下,其实NodeId是不需要的,因此,很快的改出了第二个版本,序列化后格式是这样的:
NodeCount:4bytes
//每个节点的数据
Node序列化后的长度:4bytes
Node序列化后的数据:1byte*序列化后的长度
Child的NodeId:4bytes*Child个数
......表示多个节点数据
测试了一下,长度有所减少,但是非常非常不明显,基本上是比Java序列化多了13%,还是不爽。
最后,想了一下,还是把Tree上的所有节点放到一个Array中,都交给Java序列化吧。这个时候,序列化后的格式就变为了
NodeCount:4bytes
Array序列化后的长度:4bytes
Array序列化后的内容
按照宽度优先的方式的每个TreeNode的ChildCount
这次之后,序列化后的数据和直接Java比,相差无几了,比Java直接序列化差不多少1%不到一些。