Kryo 序列化导致自定义对象发生致命 java 运行时错误
Kryo serialization caused fatal java runtime error with custom objects
我正在尝试序列化两个自定义 类(包含更多哈希图和集合)的哈希图和集合。
1 级:NodeStorage.java
@NotNull
private final String id;
@Nullable
private String type;
@Nullable
private HashMap<String, String> properties;
2 级:RelationshipStorage.java
@NotNull
private final String id;
@Nullable
private String type;
@Nullable
private HashMap<String, String> properties;
@NotNull
private final NodeStorage startNode;
@NotNull
private final NodeStorage endNode;
要序列化的集合:
private HashMap<NodeStorage, NodeStorage> readsSetNode;
private HashMap<NodeStorage, NodeStorage> updateSetNode;
private ArrayList<NodeStorage> deleteSetNode;
private ArrayList<NodeStorage> createSetNode;
private HashMap<RelationshipStorage, RelationshipStorage> readsSetRelationship;
private HashMap<RelationshipStorage, RelationshipStorage> updateSetRelationship;
private ArrayList<RelationshipStorage> deleteSetRelationship;
private ArrayList<RelationshipStorage> createSetRelationship;
到目前为止我尝试了什么:
kryo.register(NodeStorage.class, 1);
kryo.register(RelationshipStorage.class, 2);
kryo.register(HashMap.class, mapSerializer);
mapSerializer.setKeyClass(NodeStorage.class, kryo.getSerializer(NodeStorage.class));
mapSerializer.setKeyClass(RelationshipStorage.class, kryo.getSerializer(RelationshipStorage.class));
mapSerializer.setValuesCanBeNull(false);
mapSerializer.setKeysCanBeNull(false);
listSerializer.setElementClass(NodeStorage.class, kryo.getSerializer(NodeStorage.class));
listSerializer.setElementClass(RelationshipStorage.class, kryo.getSerializer(RelationshipStorage.class));
listSerializer.setElementsCanBeNull(false);
public byte[] serialize()
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Output output = new Output(stream);
mapSerializer.write(kryo, output, readsSetNode);
byte[] bytes = output.toBytes();
output.close();
return bytes;
}
我用 kryo.writeclassandobject 试过了,但效果不佳。我得到:
> > #
> # A fatal error has been detected by the Java Runtime Environment:
> #
> # SIGSEGV (0xb) at pc=0x00007f92f7f6efe0, pid=4637, tid=0x00007f92f94fd700
> #
> # JRE version: OpenJDK Runtime Environment (8.0_102-b14) (build 1.8.0_102-b14)
> # Java VM: OpenJDK 64-Bit Server VM (25.102-b14 mixed mode linux-amd64 compressed oops)
> # Problematic frame:
> # V [libjvm.so+0x787fe0]
> #
> # Core dump written
完整代码位于:https://github.com/Raycoms/thesis
声明:
private Kryo kryo = new Kryo();
MapSerializer mapSerializer = new MapSerializer();
CollectionSerializer listSerializer = new CollectionSerializer();
Kryo 不是线程安全的,实际上任何 Java 程序都有多个线程运行。例如,您的 log file 表明在崩溃时您有 25 个线程 运行。即使您的 Kryo 实例是私有的,错误也存在于 Kryo 的深处,并且那里可能存在不受您控制的线程或 JVM 交互。
尝试下面引用的线程池方法,详见 Kryo readme:
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.pool.*;
KryoFactory factory = new KryoFactory() {
public Kryo create () {
Kryo kryo = new Kryo();
// configure kryo instance, customize settings
return kryo;
}
};
// Build pool with SoftReferences enabled (optional)
KryoPool pool = new KryoPool.Builder(factory).softReferences().build();
然后,在您的 serialize()
函数中:
Kryo kryo = pool.borrow();
<... the rest of your code in serialize() before the return...>
pool.release(kryo);
return bytes;
正如 README 指出的那样,您也可以使用回调:
// or use a callback to work with kryo - no need to borrow/release,
// that's done by `run`.
String value = pool.run(new KryoCallback() {
public String execute(Kryo kryo) {
return kryo.readObject(input, String.class);
}
});
OP 的最终代码
从 OP 的评论中发布到这里,以便其他人可以更轻松地阅读它。 OP 最终无法使用 mapSerializer
,但能够使用此代码进行序列化:
private byte[] serialize() {
KryoPool pool = new KryoPool.Builder(factory).softReferences().build();
Kryo kryo = pool.borrow();
Output output = new Output(0, 1024);
kryo.writeClassAndObject(output, readsSetNode);
byte[] bytes = output.toBytes();
output.close();
pool.release(kryo);
return bytes;
}
注意 正如@MartinGrotzke 指出的那样,根据this issue,如果您使用kryo.register(class, id)
,请确保id>=10
.
我正在尝试序列化两个自定义 类(包含更多哈希图和集合)的哈希图和集合。
1 级:NodeStorage.java
@NotNull
private final String id;
@Nullable
private String type;
@Nullable
private HashMap<String, String> properties;
2 级:RelationshipStorage.java
@NotNull
private final String id;
@Nullable
private String type;
@Nullable
private HashMap<String, String> properties;
@NotNull
private final NodeStorage startNode;
@NotNull
private final NodeStorage endNode;
要序列化的集合:
private HashMap<NodeStorage, NodeStorage> readsSetNode;
private HashMap<NodeStorage, NodeStorage> updateSetNode;
private ArrayList<NodeStorage> deleteSetNode;
private ArrayList<NodeStorage> createSetNode;
private HashMap<RelationshipStorage, RelationshipStorage> readsSetRelationship;
private HashMap<RelationshipStorage, RelationshipStorage> updateSetRelationship;
private ArrayList<RelationshipStorage> deleteSetRelationship;
private ArrayList<RelationshipStorage> createSetRelationship;
到目前为止我尝试了什么:
kryo.register(NodeStorage.class, 1);
kryo.register(RelationshipStorage.class, 2);
kryo.register(HashMap.class, mapSerializer);
mapSerializer.setKeyClass(NodeStorage.class, kryo.getSerializer(NodeStorage.class));
mapSerializer.setKeyClass(RelationshipStorage.class, kryo.getSerializer(RelationshipStorage.class));
mapSerializer.setValuesCanBeNull(false);
mapSerializer.setKeysCanBeNull(false);
listSerializer.setElementClass(NodeStorage.class, kryo.getSerializer(NodeStorage.class));
listSerializer.setElementClass(RelationshipStorage.class, kryo.getSerializer(RelationshipStorage.class));
listSerializer.setElementsCanBeNull(false);
public byte[] serialize()
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Output output = new Output(stream);
mapSerializer.write(kryo, output, readsSetNode);
byte[] bytes = output.toBytes();
output.close();
return bytes;
}
我用 kryo.writeclassandobject 试过了,但效果不佳。我得到:
> > #
> # A fatal error has been detected by the Java Runtime Environment:
> #
> # SIGSEGV (0xb) at pc=0x00007f92f7f6efe0, pid=4637, tid=0x00007f92f94fd700
> #
> # JRE version: OpenJDK Runtime Environment (8.0_102-b14) (build 1.8.0_102-b14)
> # Java VM: OpenJDK 64-Bit Server VM (25.102-b14 mixed mode linux-amd64 compressed oops)
> # Problematic frame:
> # V [libjvm.so+0x787fe0]
> #
> # Core dump written
完整代码位于:https://github.com/Raycoms/thesis
声明:
private Kryo kryo = new Kryo();
MapSerializer mapSerializer = new MapSerializer();
CollectionSerializer listSerializer = new CollectionSerializer();
Kryo 不是线程安全的,实际上任何 Java 程序都有多个线程运行。例如,您的 log file 表明在崩溃时您有 25 个线程 运行。即使您的 Kryo 实例是私有的,错误也存在于 Kryo 的深处,并且那里可能存在不受您控制的线程或 JVM 交互。
尝试下面引用的线程池方法,详见 Kryo readme:
import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.pool.*; KryoFactory factory = new KryoFactory() { public Kryo create () { Kryo kryo = new Kryo(); // configure kryo instance, customize settings return kryo; } }; // Build pool with SoftReferences enabled (optional) KryoPool pool = new KryoPool.Builder(factory).softReferences().build();
然后,在您的 serialize()
函数中:
Kryo kryo = pool.borrow();
<... the rest of your code in serialize() before the return...>
pool.release(kryo);
return bytes;
正如 README 指出的那样,您也可以使用回调:
// or use a callback to work with kryo - no need to borrow/release, // that's done by `run`. String value = pool.run(new KryoCallback() { public String execute(Kryo kryo) { return kryo.readObject(input, String.class); } });
OP 的最终代码
从 OP 的评论中发布到这里,以便其他人可以更轻松地阅读它。 OP 最终无法使用 mapSerializer
,但能够使用此代码进行序列化:
private byte[] serialize() {
KryoPool pool = new KryoPool.Builder(factory).softReferences().build();
Kryo kryo = pool.borrow();
Output output = new Output(0, 1024);
kryo.writeClassAndObject(output, readsSetNode);
byte[] bytes = output.toBytes();
output.close();
pool.release(kryo);
return bytes;
}
注意 正如@MartinGrotzke 指出的那样,根据this issue,如果您使用kryo.register(class, id)
,请确保id>=10
.