【问题标题】:How does MicroStream (de)serialization work?MicroStream(反)序列化如何工作?
【发布时间】:2019-11-06 17:45:28
【问题描述】:

我想知道 MicroStream 的序列化是如何详细工作的。 既然它被描述为“超快”,它就必须依赖代码生成,对吧?还是基于反射?
与 Protobuf-Serialization 相比,它将如何执行,Protobuf-Serialization 依赖于直接读取 java 字段并将它们写入字节缓冲区的代码生成,反之亦然。
在大规模序列化​​对象时,使用反射会大大降低性能,不是吗?

我正在寻找一种快速的方法来传输和保存多人游戏中的对象,并且每一毫秒都很重要。 :)

提前致谢!

PS:由于我没有足够的声誉,我无法创建“微流”标签。 https://microstream.one/

【问题讨论】:

    标签: java serialization deserialization microstream


    【解决方案1】:

    我是 MicroStream 的首席开发人员。 (这不是别名帐户。我真的只是创建了它。我在 StackOverflow 上阅读了 10 年左右,但从未有理由创建帐户。直到现在。)

    在每次初始化时,MicroStream 都会分析所有必需实体和值类型类的当前运行时版本,并从中派生优化的元数据。 在运行时遇到迄今为止未知的类时也会这样做。 分析是针对每个反射进行的,但由于每个处理的类只进行一次,因此反射性能成本可以忽略不计。 实际的存储和加载或序列化和反序列化是通过基于创建的元数据优化的框架代码完成的。

    如果类布局发生变化,类型分析会创建从存储类实例的字段布局到当前类的映射。 如果可能,自动(明确更改或通过一些可配置的启发式),否则通过用户提供的映射。性能保持不变,因为 JVM 不关心它(简而言之)是否将加载的值 #3 复制到位置 #3 或位置 #5。都在元数据中。

    使用 ByteBuffers,更准确地说是直接 ByteBuffers,但仅作为堆外内存通过直接“不安全”低级操作工作的锚。如果您不熟悉“不安全”操作,一个简短的概念是:“它与 C++ 代码一样直接和快速。”。您可以非常快速且接近记忆地做任何您想做的事情,但您也要对所有事情负责。更多详情,谷歌“sun.misc.Unsafe”。

    没有生成代码。不使用字节码黑客、通过代理默认替换实例或类似的猴子业务。在技​​术层面上,它只是一个 Java 库(包括“不安全”用法),但有很多设计合理的逻辑。

    附带说明:反射并不像通常认为的那么慢。不再。确实如此,但在过去的一些 Java 版本中已经进行了相当多的优化。 如果每个操作都必须重新进行所有的类分析、字段查找等,这只会很慢(很多框架似乎都这样做,因为它们写得不好)。如果字段被收集(设置可访问等)一次然后缓存,反射实际上是惊人的快。

    关于与 Protobuf-Serialization 的比较:

    我无法具体说明它,因为我没有使用过 Protocol Buffers,也不知道它在内部是如何工作的。 像往常一样,对于复杂的技术,真正有意义的比较可能非常困难,因为不同的技术有不同的优化优先级和限制。

    大多数序列化方法放弃了引用一致性,但只存储“数据”(即,如果两个对象引用第三个,反序列化将创建第三个对象的两个实例。 像这样:A->C A->C1 B->C2。 这基本上会破坏/破坏/破坏对象图并使循环图的序列化成为不可能,因为它会创建并无休止地级联复制。例如,请参阅 JSON 序列化。有趣的事。) 甚至 Brian Goetz 的 Java“序列化 2.0”草案也包含该限制(参见 http://cr.openjdk.java.net/~briangoetz/amber/serialization.html 的“限制”)(以及另一个破坏关注点分离的限制)。

    MicroStream 没有这个限制。它可以正确处理任意对象图,而不会破坏它们的引用。 正如他所写,保持引用一致性的完整性到目前为止并不是“试图做太多”。它是“正确地做”。一个人只需要知道如何正确地做到这一点。如果做得正确,它甚至是相当微不足道的。 因此,根据 Protobuf-Serialization 有多少限制(“与魔鬼的约定”),它可能几乎或根本无法与 MicroStream 相比。

    当然,您始终可以针对您的特定要求创建一些性能比较测试,看看哪种技术最适合您。只需确保您了解某种技术对您施加的限制(破坏的引用一致性、禁止的类型、所需的注释、所需的默认构造函数/getter/setter 等)。 MicroStream 没有*。

    (*) 在合理范围内:序列化/存储系统内部(例如线程)或非实体(例如 lambda 或代理实例)虽然在技术上是可行的,但有意排除在外。

    【讨论】:

    • 非常感谢您非常详细的回答,这听起来很棒!尤其是在反序列化期间将对象引用放在一起听起来很神奇。我会做一些原型设计,看看它是否适合我的游戏。我认为棘手的是我不仅需要存储它们,还需要在客户端和服务器之间发送序列化的对象,而客户端需要再次反序列化它们。
    猜你喜欢
    • 2014-01-24
    • 1970-01-01
    • 2023-02-14
    • 2015-09-22
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多