首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java 8中可序列化lambda的性能

Java 8中可序列化lambda的性能
EN

Stack Overflow用户
提问于 2015-01-07 16:05:15
回答 2查看 1K关注 0票数 5

我在Brian的一些评论中看到,可序列化的lambdas“比不可序列化的lambdas具有更高的性能成本”。

我现在很好奇:这到底是在哪里?是什么造成的?它是只影响lambda的实例化,还是在调用中影响?

在下面的代码中,这两种情况( callExistingInstance()和callWithNewInstance() )是否都会受到"MyFunction“的可序列化性的影响,还是只受第二种情况的影响?

代码语言:javascript
复制
interface MyFunction<IN, OUT> {
    OUT call(IN arg);
}

void callExistingInstance() {

    long toAdd = 1;
    long value = 0;

    final MyFunction<Long, Long> adder = (number) -> number + toAdd;

    for (int i = 0; i < LARGE_NUMBER; i++) {
        value = adder.call(value);
    }
}

void callWithNewInstance() {

    long value = 0;

    for (int i = 0; i < LARGE_NUMBER; i++) {
        long toAdd = 1;

        MyFunction<Long, Long> adder = (number) -> number + toAdd;

        value = adder.call(value);
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-07 16:19:37

当您序列化/反序列化和实例化时,性能就会受到影响。只有你的第二个例子受到打击。其原因是,当反序列化时,lambda的底层类被某种特殊反射(它能够创建/定义类)实例化,而不是普通的旧序列化对象(类定义来自哪里?),以及执行一些安全检查.

票数 4
EN

Stack Overflow用户

发布于 2015-01-12 17:49:27

通常,lambda实现的运行时部分将生成一个类,该类基本上由一个实现方法组成。生成这样一个类所需的信息是通过在运行时对LambdaMetafactory.metafactory的引导方法调用提供的。

当启用序列化时,事情会变得更加复杂。首先,编译后的代码将使用替代的引导方法LambdaMetafactory.altMetafactory,它提供了更大的灵活性,代价是必须根据参数数组中指定的标志解析varargs参数。

然后,生成的lambda类必须有一个writeReplace方法(参见 documentation的下半部分),该方法必须创建并返回一个包含重新创建lambda实例所需的所有信息的SerializedLambda实例。由于lambda类的单个实现方法只包含一个简单的委托调用,所以writeReplace方法和相关的常量信息将乘以生成的类的大小。

还值得注意的是,创建可序列化的lambda实例的类将有一个合成方法$deserializeLambda$ (将SerializedLambda与lambda的writeReplace进程相比较。这将增加类的磁盘使用量和加载时间(但不会影响lambda表达式的计算)。

在示例代码中,这两个方法都会受到与引导和类生成相同的时间的影响,每个lambda表达式只发生一次。在随后的评估中, created (if not even the instance is re-used)。我们在这里讨论的是一次性开销,即使lambda表达式包含在循环中,它也只影响第一次迭代。

请注意,如果在循环中有一个lambda表达式,则可能会为每个迭代创建一个新实例,而在整个循环期间,在循环外使其具有一个实例。但这种行为并不取决于目标接口是否为Serializable的问题。这仅仅取决于表达式是否捕获值(与this answer相比)。

注意如果你写了

代码语言:javascript
复制
final long toAdd = 1;
MyFunction<Long, Long> adder = (number) -> number + toAdd;

在第二个方法(请注意显式final修饰符)中,值toAdd将是一个编译时常量,如果您编写了(number) -> number + 1,即不再捕获值,表达式就会被编译。然后,您将在每个循环迭代中获得相同的lambda实例(使用Oracle当前版本的JVM)。因此,新实例是否创建的问题有时取决于上下文的一些小部分。但通常情况下,对性能的影响相当小。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27823516

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档