通过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和流的原因是什么?可能的影响是什么?
插图有助于更好地理解,而不是在这里寻找意见。
答案 0 :(得分:10)
不依赖于lambdas和流(广泛使用lambdas)有助于避免在VM引导程序中执行冗余工作。这反过来又减少了启动时间和内存占用。
JDK中的 invokedynamic
机制相当复杂。它涉及许多与方法句柄,Lambda Metafactories等相关的java.lang.invoke.*
类,需要加载和初始化。此外,链接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 ms和537个加载类,而Lambda
需要161 ms和620个加载类。
因此,在这个简单的例子中,避免单个lambda有助于节省25毫秒的启动时间,减少了83个类的加载。
修改强>
我所描述的开销包括两部分:
java.lang.invoke.*
类 - 这是需要仅执行一次的常量部分。