Kryo Attention

com.esotericsoftware.kryo.KryoException: Encountered unregistered class ID: XXXX

当Kryo写出一个对象的实例时,首先可能需要写出一些标识对象类的东西。默认情况下,写入完整类名,然后写入该对象的字节。后续出现的同一类对象图的对象用变长的int来写(using a variable length int)。

写类的名字有点低效,所以类可以事先注册:kryo.register(SomeClass.class);这样的话,SomeClass 注册到了 Kryo,它将该类与一个 int 型的 ID 相关联。当 Kryo 写出 SomeClass 的一个实例时,它会写出这个 int ID。这比写出类名更有效。在反序列化期间,注册的类必须具有序列化期间相同的 ID 。还有一种情况是kryo每次写入类的完整信息,而不是通过int类型的ID号去代替。

两种情况如何取舍呢?写id的情况,效率会高一些,但是缺陷很明显:所有系列化涉及到的类都需要代码里手工kryo.register(),否则报告unregistered class ID;另外,kryo不能保证”每次jvm重启之后,或者在多台jvm机器之间,同一个类注册到kryo的class ID会相同”,所以这就导致该模式应用于集群会存在严重问题,所以用id代替类信息的模式不建议使用,而且,默认该功能也是关闭的,除非你在代码中显性的调用了以下代码:

1
2
3
kryo.register(SomeClass.class);
// 或者:
Kryo.setRegistrationRequired(true);

所以遇到Encountered unregistered class ID之类的问题,首先要检查该功能是否被不经意的开启了。如果确保未开启该功能,再考虑以下情况:就是对象太大,导致系列化结果不完整,因为output对象默认的缓存字节数并不大,实际对象超出大小的时候,系列化的时候并不会报告错误,但是系列化结果已经不完整,从而导致反系列化的时候会失败,报告的错误一般也是Encountered unregistered class ID。

com.esotericsoftware.kryo.KryoException: Buffer underflow.

  • 检查反序列化数据与反序列化类是否一致,如果当前数据与反序列化类不一致,有可能抛出该异常。

can’t serializer AtomicDouble

默认情况下序列化AtomicDouble,再反序列化回来,AtomicDouble里面的数值为0.0,即数据丢失了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Serializer for AtomicDouble (needs a serializer due to long field being transient...)
*/
public class AtomicDoubleSerializer extends Serializer<AtomicDouble> {
@Override
public void write(Kryo kryo, Output output, AtomicDouble a) {
output.writeDouble(a.get());
}

@Override
public AtomicDouble read(Kryo kryo, Input input, Class<AtomicDouble> a) {
return new AtomicDouble(input.readDouble());
}
}