的一类通过java.lang.module
去避免Lambda和流使用我读之间的一类文档以下:在VM启动
@implNote ... is used at VM startup and so deliberately avoids using lambda and stream usages in code paths used during startup.
什么是使用拉姆达的原因和流是在这里可以避免,它们可能产生什么影响?
插图将有助于更好地理解,而不是在这里寻找意见。
的一类通过java.lang.module
去避免Lambda和流使用我读之间的一类文档以下:在VM启动
@implNote ... is used at VM startup and so deliberately avoids using lambda and stream usages in code paths used during startup.
什么是使用拉姆达的原因和流是在这里可以避免,它们可能产生什么影响?
插图将有助于更好地理解,而不是在这里寻找意见。
不依赖于lambdas和流(广泛使用lambda表达式)有助于避免在虚拟机引导时做冗余工作。这反过来又减少了启动时间和内存占用。
invokedynamic
JDK中的机器相当复杂。它涉及许多与方法句柄,Lambda元函数等有关的类,这些类需要加载和初始化。此外,链接invokedynamic
字节码JVM使用ObjectWeb ASM框架动态创建适配器。在运行时生成这样的类也需要时间和空间。
让我们测量在非常基本的场景中使用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个加载的类。
编辑
我所描述的开销由两个部分组成:
java.lang.invoke.*
类 - 这是一个必须做一次恒定的一部分。另外,假设这里并提出,如果这可能会被添加到答案。 *单个lambda有助于节省25毫秒的启动时间,并减少了83个加载的类。*但这种增长会呈指数级增长,而不是乘以lambda的数量。我对么? – nullpointer
@nullpointer我已经更新了答案。开销与lambda表达式的数量以及加载和初始化其他类所需的常量开销成正比。 – apangin
你使用的是'jdk9'吗?我想,它还没有发布。对 ? – Ravi
@Ravi是的,我([early access build](http://jdk.java.net/9/))。这个问题与它的发布没有关系,而是一个实现。 – nullpointer
但是,如果有什么东西没有发布,那么怎么能有人告诉你他们的用法? – Ravi