gpt4 book ai didi

java - 避免 VM 启动时使用的类使用 lambda 和流

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:58:01 31 4
gpt4 key购买 nike

通过 java.lang.module 我在类文档中阅读了以下内容:

@implNote ... is used at VM startup and so deliberately
avoids using lambda and stream usages in code paths used during
startup.

使用此处避免的 lambda 和流的原因是什么?它们可能产生的影响是什么?

插图将有助于更好地理解,但不是在这里寻求意见。

最佳答案

不依赖 lambda 和流(广泛使用 lambda)有助于避免在 VM Bootstrap 中进行冗余工作。这反过来又减少了启动时间和内存占用。

invokedynamic JDK 中的机制相当复杂。它涉及许多java.lang.invoke.* 类,与方法句柄、Lambda 元工厂等相关,需要加载和初始化。此外,为了链接 invokedynamic 字节码,JVM 使用 ObjectWeb ASM 框架动态创建适配器。在运行时生成这样的类也需要时间和空间。

让我们测量一下在非常基本的场景中使用 lambda 而不是内部类的开销。我创建了两个类似的类,它们除了实例化内部类或 lambda 之外什么都不做:

class Inner {
public static void main(String[] args) {
Runnable r = new Runnable() { public void run() {} };
r.run();
}
}

class Lambda {
public static void main(String[] args) {
Runnable r = () -> {};
r.run();
}
}

然后我在打开类加载日志的情况下运行:

java -Xlog:class+load:file=inner.log Inner
java -Xlog:class+load:file=lambda.log Lambda

inner.log

[0.011s][info][class,load] opened: C:\Program Files\Java\jdk-9\lib\modules
[0.022s][info][class,load] java.lang.Object source: jrt:/java.base
[0.022s][info][class,load] java.io.Serializable source: jrt:/java.base
...
[0.136s][info][class,load] Inner$1 source: file:/C:/Andrei/
[0.136s][info][class,load] java.lang.Shutdown source: jrt:/java.base
[0.136s][info][class,load] java.lang.Shutdown$Lock source: jrt:/java.base

lambda.log

[0.011s][info][class,load] opened: C:\Program Files\Java\jdk-9\lib\modules
[0.022s][info][class,load] java.lang.Object source: jrt:/java.base
[0.022s][info][class,load] java.io.Serializable source: jrt:/java.base
...
[0.159s][info][class,load] Lambda$$Lambda$1/1282788025 source: Lambda
[0.159s][info][class,load] java.lang.invoke.InnerClassLambdaMetafactory$1 source: jrt:/java.base
[0.159s][info][class,load] java.lang.invoke.MethodHandleImpl$IntrinsicMethodHandle source: jrt:/java.base
[0.159s][info][class,load] java.lang.invoke.SimpleMethodHandle source: jrt:/java.base
[0.159s][info][class,load] sun.invoke.util.Wrapper$1 source: jrt:/java.base
[0.160s][info][class,load] java.lang.invoke.LambdaForm$MH/100555887 source: java.lang.invoke.LambdaForm
[0.160s][info][class,load] java.lang.invoke.LambdaForm$MH/1983747920 source: java.lang.invoke.LambdaForm
[0.160s][info][class,load] java.lang.Shutdown source: jrt:/java.base
[0.161s][info][class,load] java.lang.Shutdown$Lock source: jrt:/java.base

完整的输出是here .正如我们所见,Inner 需要 136 毫秒和 537 个加载类,而 Lambda 需要 161 毫秒和 620 个加载类。

因此,在这个简单的示例中,避免使用单个 lambda 有助于节省 25 毫秒的启动时间,同时减少加载 83 个类。

编辑

我描述的开销由两部分组成:

  1. 加载和初始化 java.lang.invoke.* 类 - 这是常量部分,只需完成一次。
  2. 链接特定的 lambda 调用站点 - 这需要调用 LambdaMetafactory Bootstrap 方法并生成用于调用目标方法的运行时适配器。这需要为每个 lambda 完成,因此这部分开销与代码中的 lambda 数量成正比。

关于java - 避免 VM 启动时使用的类使用 lambda 和流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45902215/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com